home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 February / PCWorld_2006-02_cd.bin / software / vyzkuste / triky / triky.exe / httrack-3.33.exe / {app} / src / htsback.c < prev    next >
C/C++ Source or Header  |  2004-10-29  |  120KB  |  3,007 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       backing system (multiple socket download)              */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htsback.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htsnet.h"
  46. #include "htsthread.h"
  47. #include <time.h>
  48. /* END specific definitions */
  49.  
  50. //#if HTS_WIN
  51. #include "htsftp.h"
  52. #if HTS_USEZLIB
  53. #include "htszlib.h"
  54. #else
  55. #error HTS_USEZLIB not defined
  56. #endif
  57. //#endif
  58.  
  59. #if HTS_WIN
  60. #ifndef __cplusplus
  61. // DOS
  62. #ifndef  _WIN32_WCE
  63. #include <process.h>    /* _beginthread, _endthread */
  64. #endif
  65. #endif
  66. #else
  67. #endif
  68.  
  69. #undef test_flush
  70. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->errlog) { fflush(opt->errlog);  } }
  71.  
  72. #define VT_CLREOL       "\33[K"
  73.  
  74.  
  75. // ---
  76. // routines de backing
  77. // retourne l'index d'un lien dans un tableau de backing
  78. int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  79.   int i=0;
  80.   int index=-1;
  81.   while( i<back_max ) {
  82.     if (back[i].status>=0)    // rΘception OU prΩt
  83.       if (strfield2(back[i].url_adr,adr)) {
  84.         if (strcmp(back[i].url_fil,fil)==0) {
  85.           if (index==-1)    /* first time we meet, store it */
  86.             index=i;
  87.           else if (strcmp(back[i].url_sav,sav)==0) {  /* oops, check sav too */
  88.             index=i;
  89.             return index;
  90.           }
  91.         }
  92.       }
  93.     i++;
  94.   }
  95.   return index;
  96. }
  97.  
  98. // nombre d'entrΘes libres dans le backing
  99. int back_available(lien_back* back,int back_max) {
  100.   int i;
  101.   int nb=0;
  102.   for(i=0;i<back_max;i++)
  103.     if (back[i].status==-1)     /* libre */
  104.       nb++;
  105.   return nb;
  106. }
  107.  
  108. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  109. LLint back_incache(lien_back* back,int back_max) {
  110.   int i;
  111.   LLint sum=0;
  112.   for(i=0;i<back_max;i++)
  113.     if (back[i].status!=-1)
  114.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  115.         sum+=max(back[i].r.size,back[i].r.totalsize);
  116.   return sum;
  117. }
  118.  
  119. // le lien a-t-il ΘtΘ mis en backing?
  120. HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  121.   return (back_index(back,back_max,adr,fil,sav)>=0);
  122. }
  123.  
  124. // nombre de sockets en tΓche de fond
  125. int back_nsoc(lien_back* back,int back_max) {
  126.   int n=0;
  127.   int i;
  128.   for(i=0;i<back_max;i++)
  129.     if (back[i].status > 0)    // only receive
  130.       n++;
  131.  
  132.   return n;
  133. }
  134. int back_nsoc_overall(lien_back* back,int back_max) {
  135.   int n=0;
  136.   int i;
  137.   for(i=0;i<back_max;i++)
  138.     if (back[i].status > 0 || back[i].status == -103)
  139.       n++;
  140.  
  141.   return n;
  142. }
  143.  
  144. // objet (lien) tΘlΘchargΘ ou transfΘrΘ depuis le cache
  145. //
  146. // fermer les paramΦtres de transfert,
  147. // et notamment vΘrifier les fichiers compressΘs (dΘcompresser), callback etc.
  148. int back_finalize(httrackp* opt,cache_back* cache,lien_back* back,int p) {
  149.   /* Don't store broken files */
  150.   if (back[p].r.totalsize > 0 && back[p].r.size != back[p].r.totalsize && ! opt->tolerant) {
  151.     return -1;
  152.   }
  153.  
  154.   /* Store ? */
  155.   if (!back[p].finalized) {
  156.     back[p].finalized = 1;
  157.     if (
  158.       (back[p].status == 0)      // ready
  159.       &&
  160.       (back[p].r.statuscode>0)   // not internal error
  161.       ) {
  162.       if (!back[p].testmode) {        // not test mode
  163.       char* state="unknown";
  164.       
  165.       /* dΘcompression */
  166. #if HTS_USEZLIB
  167.       if (gz_is_available && back[p].r.compressed) {
  168.         if (back[p].r.size > 0) {
  169.           //if ( (back[p].r.adr) && (back[p].r.size>0) ) {
  170.           // stats
  171.           back[p].compressed_size=back[p].r.size;
  172.           // en mΘmoire -> passage sur disque
  173.           if (!back[p].r.is_write) {
  174.             back[p].tmpfile_buffer[0]='\0';
  175.             back[p].tmpfile=tmpnam(back[p].tmpfile_buffer);
  176.             if (back[p].tmpfile != NULL && back[p].tmpfile[0] != '\0') {
  177.               back[p].r.out=fopen(back[p].tmpfile,"wb");
  178.               if (back[p].r.out) {
  179.                 if ((back[p].r.adr) && (back[p].r.size>0)) {
  180.                   if (fwrite(back[p].r.adr,1,(INTsys)back[p].r.size,back[p].r.out) != back[p].r.size) {
  181.                     back[p].r.statuscode=-1;
  182.                     strcpybuff(back[p].r.msg,"Write error when decompressing");
  183.                   }
  184.                 } else {
  185.                   back[p].tmpfile[0]='\0';
  186.                   back[p].r.statuscode=-1;
  187.                   strcpybuff(back[p].r.msg,"Empty compressed file");
  188.                 }
  189.               } else {
  190.                 back[p].tmpfile[0]='\0';
  191.                 back[p].r.statuscode=-1;
  192.                 strcpybuff(back[p].r.msg,"Open error when decompressing");
  193.               }
  194.             }
  195.           }
  196.           // fermer fichier sortie
  197.           if (back[p].r.out!=NULL) {
  198.             fclose(back[p].r.out);
  199.             back[p].r.out=NULL;
  200.           }
  201.           // dΘcompression
  202.           if (back[p].tmpfile != NULL && back[p].tmpfile[0] != '\0' && back[p].url_sav[0]) {
  203.             LLint size;
  204.             filecreateempty(back[p].url_sav);      // filenote & co
  205.             if ((size = hts_zunpack(back[p].tmpfile,back[p].url_sav))>=0) {
  206.               back[p].r.size=back[p].r.totalsize=size;
  207.               // fichier -> mΘmoire
  208.               if (!back[p].r.is_write) {
  209.                 deleteaddr(&back[p].r);
  210.                 back[p].r.adr=readfile(back[p].url_sav);
  211.                 if (!back[p].r.adr) {
  212.                   back[p].r.statuscode=-1;
  213.                   strcpybuff(back[p].r.msg,"Read error when decompressing");
  214.                 }
  215.                 remove(back[p].url_sav);
  216.               }
  217.             }
  218.             remove(back[p].tmpfile);
  219.           }
  220.           // stats
  221.           HTS_STAT.total_packed+=back[p].compressed_size;
  222.           HTS_STAT.total_unpacked+=back[p].r.size;
  223.           HTS_STAT.total_packedfiles++;
  224.           // unflag
  225.         }
  226.       }
  227.       back[p].r.compressed=0;
  228. #endif
  229.       
  230.       /* Stats */
  231.       if (cache->txt) {
  232.         char flags[32];
  233.         char s[256];
  234.         time_t tt;
  235.         struct tm* A;
  236.         tt=time(NULL);
  237.         A=localtime(&tt);
  238.         if (A == NULL) {
  239.           int localtime_returned_null=0;
  240.           assert(localtime_returned_null);
  241.         }
  242.         strftime(s,250,"%H:%M:%S",A);
  243.         
  244.         flags[0]='\0';
  245.         /* input flags */
  246.         if (back[p].is_update)
  247.           strcatbuff(flags, "U");   // update request
  248.         else
  249.           strcatbuff(flags, "-");
  250.         if (back[p].range_req_size)
  251.           strcatbuff(flags, "R");   // range request
  252.         else
  253.           strcatbuff(flags, "-");
  254.         /* state flags */
  255.         if (back[p].r.is_file)  // direct to disk
  256.           strcatbuff(flags, "F");
  257.         else
  258.           strcatbuff(flags, "-");
  259.         /* output flags */
  260.         if (!back[p].r.notmodified)
  261.           strcatbuff(flags, "M");   // modified
  262.         else
  263.           strcatbuff(flags, "-");
  264.         if (back[p].r.is_chunk)  // chunked
  265.           strcatbuff(flags, "C");
  266.         else
  267.           strcatbuff(flags, "-");
  268.         if (back[p].r.compressed)
  269.           strcatbuff(flags, "Z");   // gzip
  270.         else
  271.           strcatbuff(flags, "-");
  272.         /* Err I had to split these.. */
  273.         fprintf(cache->txt,"%s\t", s);
  274.         fprintf(cache->txt,LLintP"/", (LLint)back[p].r.size);
  275.         fprintf(cache->txt,LLintP,(LLint)back[p].r.totalsize);
  276.         fprintf(cache->txt,"\t%s\t",flags);
  277.       }
  278.       if (back[p].r.statuscode==200) {
  279.         if (back[p].r.size>=0) {
  280.           if (strcmp(back[p].url_fil,"/robots.txt") !=0 ) {
  281.             HTS_STAT.stat_bytes+=back[p].r.size;
  282.             HTS_STAT.stat_files++;
  283.           }
  284.           if ( (!back[p].r.notmodified) && (opt->is_update) ) { 
  285.             HTS_STAT.stat_updated_files++;       // page modifiΘe
  286.             if (opt->log!=NULL) {
  287.               fspc(opt->log,"info");
  288.               if (back[p].is_update) {
  289.                 fprintf(opt->log,"engine: transfer-status: link updated: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  290.               } else {
  291.                 fprintf(opt->log,"engine: transfer-status: link added: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  292.               }
  293.               test_flush;
  294.             }
  295.             if (cache->txt) {
  296.               if (back[p].is_update) {
  297.                 state="updated";
  298.               } else {
  299.                 state="added";
  300.               }
  301.             }
  302.           } else {
  303.             if ( (opt->debug>0) && (opt->log!=NULL) ) {
  304.               fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link recorded: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  305.               test_flush;
  306.             }
  307.             if (cache->txt) {
  308.               if (opt->is_update)
  309.                 state="untouched";
  310.               else
  311.                 state="added";
  312.             }
  313.           }
  314.         } else {
  315.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  316.             fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: empty file? (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  317.             test_flush;
  318.           }
  319.           if (cache->txt) {
  320.             state="empty";
  321.           }
  322.         }
  323.       } else {
  324.         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  325.           fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link error (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  326.         }
  327.         if (cache->txt) {
  328.           state="error";
  329.         }
  330.       }
  331.       if (cache->txt) {
  332.         fprintf(cache->txt,
  333.           "%d\t"
  334.           "%s ('%s')\t"
  335.           "%s\t"
  336.           "%s%s\t"
  337.           "%s%s\t%s\t"
  338.           "(from %s%s)"
  339.           LF,
  340.           back[p].r.statuscode,
  341.           state, escape_check_url_addr(back[p].r.msg),
  342.           escape_check_url_addr(back[p].r.contenttype),
  343.           ((back[p].r.etag[0])?"etag:":((back[p].r.lastmodified[0])?"date:":"")), escape_check_url_addr((back[p].r.etag[0])?back[p].r.etag:(back[p].r.lastmodified)),
  344.           escape_check_url_addr(back[p].url_adr),escape_check_url_addr(back[p].url_fil),escape_check_url_addr(back[p].url_sav),
  345.           escape_check_url_addr(back[p].referer_adr),escape_check_url_addr(back[p].referer_fil)
  346.           );
  347.         if (opt->flush)
  348.           fflush(cache->txt);
  349.       }
  350.       
  351.       /* Cache */
  352.       cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  353.       
  354.       // status finished callback
  355. #if HTS_ANALYSTE
  356.       hts_htmlcheck_xfrstatus(&back[p]);
  357. #endif
  358.       return 0;
  359.   } else {        // testmode
  360.     if (back[p].r.statuscode / 100 >= 3) {        /* Store 3XX, 4XX, 5XX test response codes, but NOT 2XX */
  361.       /* Cache */
  362.       cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,NULL);
  363.     }
  364.   }
  365.   }
  366.   }
  367.   return -1;
  368. }
  369.  
  370. /* try to keep the connection alive */
  371. int back_letlive(httrackp* opt, cache_back* cache, lien_back* back, int p) {
  372.   int checkerror;
  373.   htsblk* src = &back[p].r;
  374.   if (src && !src->is_file 
  375.     && src->soc != INVALID_SOCKET
  376.     && src->statuscode >= 0           /* no timeout errors & co */
  377.     && src->keep_alive_trailers == 0  /* not yet supported (chunk trailers) */
  378.     && ! ( checkerror = check_sockerror(src->soc) )
  379.     /*&& !check_sockdata(src->soc)*/     /* no unexpected data */
  380.     ) {
  381.     htsblk tmp;
  382.     memset(&tmp, 0, sizeof(tmp));
  383.     /* clear everything but connection: switch, close, and reswitch */
  384.     back_connxfr(src, &tmp);
  385.     back_delete(opt, cache, back, p);
  386.     //deletehttp(src);
  387.     back_connxfr(&tmp, src);
  388.     src->req.flush_garbage=1;     /* ignore CRLF garbage */
  389.     return 1;
  390.   }
  391.   return 0;
  392. }
  393.  
  394. void back_connxfr(htsblk* src, htsblk* dst) {
  395.   dst->soc = src->soc;
  396.   src->soc = INVALID_SOCKET;
  397. #if HTS_USEOPENSSL
  398.   dst->ssl = src->ssl;
  399.   src->ssl = 0;
  400.   dst->ssl_con = src->ssl_con;
  401.   src->ssl_con = NULL;
  402. #endif
  403.   dst->keep_alive = src->keep_alive;
  404.   src->keep_alive = 0;
  405.   dst->keep_alive_max = src->keep_alive_max;
  406.   src->keep_alive_max = 0;
  407.   dst->keep_alive_t = src->keep_alive_t;
  408.   src->keep_alive_t = 0;
  409.   dst->debugid = src->debugid;
  410.   src->debugid = 0;
  411. }
  412.  
  413. // clear, or leave for keep-alive
  414. int back_maydelete(httrackp* opt,cache_back* cache,lien_back* back, int p) {
  415.   if (p>=0) {    // on sait jamais..
  416.     if (
  417.       /* Keep-alive authorized by user */
  418.       !opt->nokeepalive
  419.       /* Socket currently is keep-alive! */
  420.       && back[p].r.keep_alive 
  421.       /* Remaining authorized requests */
  422.       && back[p].r.keep_alive_max > 1
  423.       /* Known keep-alive start (security) */
  424.       && back[p].ka_time_start 
  425.       /* We're on time */
  426.       && time_local() < back[p].ka_time_start + back[p].r.keep_alive_t
  427.       /* Connection delay must not exceed keep-alive timeout */
  428.       && ( opt->maxconn <= 0 || ( back[p].r.keep_alive_t > ( 1.0 / opt->maxconn ) ) )
  429.       ) {
  430.       lien_back tmp;
  431.       strcpybuff(tmp.url_adr, back[p].url_adr);
  432.       if (back_letlive(opt, cache, back, p)) {
  433.         strcpybuff(back[p].url_adr, tmp.url_adr);
  434.         back[p].status = -103;  // alive & waiting
  435.         if ((opt->debug>1) && (opt->log!=NULL)) {
  436.           fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully saved #%d (%s)"LF, 
  437.             back[p].r.debugid,
  438.             back[p].url_adr); test_flush;
  439.         }
  440.         return 1;
  441.       }
  442.     }
  443.     back_delete(opt,cache,back, p);
  444.   }
  445.   return 0;
  446. }
  447.  
  448. // clear, or leave for keep-alive
  449. void back_maydeletehttp(httrackp* opt, cache_back* cache, lien_back* back, int back_max, int p) {
  450.   TStamp lt = 0;
  451.   if (back[p].r.soc!=INVALID_SOCKET) {
  452.     int q;
  453.     if (
  454.       back[p].r.soc != INVALID_SOCKET        /* security check */
  455.       && back[p].r.statuscode >= 0           /* no timeout errors & co */
  456.       && back[p].r.keep_alive_trailers == 0  /* not yet supported (chunk trailers) */
  457.       /* Socket not in I/O error status */
  458.       && !back[p].r.is_file
  459.       && !check_sockerror(back[p].r.soc)
  460.       /* Keep-alive authorized by user */
  461.       && !opt->nokeepalive
  462.       /* Socket currently is keep-alive! */
  463.       && back[p].r.keep_alive 
  464.       /* Remaining authorized requests */
  465.       && back[p].r.keep_alive_max > 1
  466.       /* Known keep-alive start (security) */
  467.       && back[p].ka_time_start 
  468.       /* We're on time */
  469.       && ( lt = time_local() ) < back[p].ka_time_start + back[p].r.keep_alive_t
  470.       /* Connection delay must not exceed keep-alive timeout */
  471.       && ( opt->maxconn <= 0 || ( back[p].r.keep_alive_t > ( 1.0 / opt->maxconn ) ) )
  472.       /* Available slot in backing */
  473.       && ( q = back_search(opt, cache, back, back_max) ) >= 0
  474.       ) 
  475.     {
  476.       lien_back tmp;
  477.       strcpybuff(tmp.url_adr, back[p].url_adr);
  478.       deletehttp(&back[q].r);               // security check
  479.       back_connxfr(&back[p].r, &back[q].r); // transfer live connection settings from p to q
  480.       back[q].ka_time_start = back[p].ka_time_start;  // refresh
  481.       back[p].r.soc = INVALID_SOCKET;
  482.       strcpybuff(back[q].url_adr, tmp.url_adr); // address
  483.       back[q].status = -103;  // alive & waiting
  484.       if ((opt->debug>1) && (opt->log!=NULL)) {
  485.         fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully preserved #%d (%s)"LF, 
  486.           back[q].r.debugid,
  487.           back[q].url_adr); test_flush;
  488.       }
  489.     } else {
  490.       deletehttp(&back[p].r);
  491.       back[p].r.soc = INVALID_SOCKET;
  492.     }
  493.   }
  494. }
  495.  
  496.  
  497. /* attempt to attach a live connection to this slot */
  498. int back_trylive(httrackp* opt,cache_back* cache,lien_back* back, int back_max, int p) {
  499.   if (p>=0 && back[p].status != -103) {     // we never know..
  500.     int i = back_searchlive(opt,back, back_max, back[p].url_adr);   // search slot
  501.     if (i >= 0 && i != p) {
  502.       deletehttp(&back[p].r);               // security check
  503.       back_connxfr(&back[i].r, &back[p].r); // transfer live connection settings from i to p
  504.       back_delete(opt,cache,back, i);                 // delete old slot
  505.       back[p].status=100;                   // ready to connect
  506.       return 1;                             // success: will reuse live connection
  507.     }
  508.   }
  509.   return 0;
  510. }
  511.  
  512. /* search for a live position, or, if not possible, try to return a new one */
  513. int back_searchlive(httrackp* opt, lien_back* back, int back_max, char* search_addr) {
  514.   int i;
  515.  
  516.   /* search for a live socket */
  517.   for(i = 0 ; i < back_max ; i++ ) {
  518.     if (back[i].status == -103) {
  519.       if (strfield2(back[i].url_adr, search_addr)) {   /* same location (xxc: check also virtual hosts?) */
  520.         if (time_local() < back[i].ka_time_start + back[i].r.keep_alive_t) {
  521.           return i;
  522.         }
  523.       }
  524.     }
  525.   }
  526.   return -1;
  527. }
  528.   
  529. int back_search(httrackp* opt,cache_back* cache,lien_back* back, int back_max) {
  530.   int i;
  531.  
  532.   /* try to find an empty place */
  533.   for(i = 0 ; i < back_max ; i++ ) {
  534.     if (back[i].status == -1) {
  535.       return i;
  536.     }
  537.   }
  538.  
  539.   /* couldn't find an empty place, try to requisition a keep-alive place */
  540.   for(i = 0 ; i < back_max ; i++ ) {
  541.     if (back[i].status == -103) {
  542.       /* close this place */
  543.       back_delete(opt,cache,back, i);
  544.       return i;
  545.     }
  546.   }
  547.  
  548.   /* oops, can't find a place */
  549.   return -1;
  550. }
  551.  
  552. // effacer entrΘe
  553. int back_delete(httrackp* opt, cache_back* cache, lien_back* back, int p) {
  554.   if (p>=0) {    // on sait jamais..
  555.     // VΘrificateur d'intΘgritΘ
  556.     #if DEBUG_CHECKINT
  557.     _CHECKINT(&back[p],"Appel back_delete")
  558.     #endif
  559. #if HTS_DEBUG_CLOSESOCK
  560.     DEBUG_W("back_delete: #%d\n" _ (int) p);
  561. #endif
  562.     
  563.     // Finalize
  564.     if (!back[p].finalized) {
  565.       if (
  566.         (back[p].status == 0)      // ready
  567.         &&
  568.         (!back[p].testmode)        // not test mode
  569.         &&
  570.         (back[p].r.statuscode>0)   // not internal error
  571.         ) {
  572.         if ((opt->debug>1) && (opt->log!=NULL)) {
  573.           fspc(opt->log,"debug"); fprintf(opt->log,"File '%s%s' -> %s not yet saved in cache - saving now"LF, back[p].url_adr, back[p].url_fil, back[p].url_sav); test_flush;
  574.         }
  575.       }
  576.       back_finalize(opt, cache, back, p);
  577.     }
  578.     back[p].finalized = 0;
  579.     
  580.     // LibΘrer tous les sockets, handles, buffers..
  581.     if (back[p].r.soc!=INVALID_SOCKET) {
  582. #if HTS_DEBUG_CLOSESOCK
  583.       DEBUG_W("back_delete: deletehttp\n");
  584. #endif
  585.       deletehttp(&back[p].r);
  586.       back[p].r.soc=INVALID_SOCKET;
  587.     }
  588.     
  589.     if (back[p].r.adr!=NULL) {  // reste un bloc α dΘsallouer
  590.       freet(back[p].r.adr);
  591.       back[p].r.adr=NULL;
  592.     }
  593.     if (back[p].chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  594.       freet(back[p].chunk_adr);
  595.       back[p].chunk_adr=NULL;
  596.       back[p].chunk_size=0;
  597.       back[p].chunk_blocksize=0;
  598.       back[p].is_chunk=0;
  599.     }
  600.     // if (back[p].r.is_file) {  // fermer fichier entrΘe
  601.     if (back[p].r.fp!=NULL) {
  602.       fclose(back[p].r.fp);
  603.       back[p].r.fp=NULL;
  604.     }
  605.     // }
  606.  
  607.     // headers
  608.     if (back[p].r.headers != NULL) {
  609.       freet(back[p].r.headers);
  610.       back[p].r.headers = NULL;
  611.     }
  612.  
  613.     /* fichier de sortie */
  614.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  615.       fclose(back[p].r.out);
  616.       back[p].r.out=NULL;
  617.     }
  618.  
  619.     if (back[p].r.is_write) {     // ecriture directe
  620.       /* Θcrire date "remote" */
  621.       if (strnotempty(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  622.       if (strnotempty(back[p].r.lastmodified))   // last-modified existe
  623.       if (fexist(back[p].url_sav))          // ainsi que le fichier
  624.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  625.  
  626.       /* executer commande utilisateur aprΦs chargement du fichier */
  627.       //xx usercommand(opt,0,NULL,back[p].url_sav, back[p].url_adr, back[p].url_fil);
  628.       back[p].r.is_write=0;
  629.     }
  630.     
  631.     // Tout nettoyer
  632.     memset(&back[p], 0, sizeof(lien_back));  
  633.     back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  634.     
  635.     // Le plus important: libΘrer le champ
  636.     back[p].status=-1;
  637.   }
  638.   return 0;
  639. }
  640.  
  641. /* Space left on backing stack */
  642. int back_stack_available(lien_back* back,int back_max) {
  643.   int p=0,n=0;
  644.   for( ; p < back_max ; p++ )
  645.     if ( back[p].status == -1 )
  646.       n++;
  647.   return n;
  648. }
  649.  
  650. // ajouter un lien en backing
  651. int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test,int* pass2_ptr) {
  652.   int p=0;
  653.  
  654.   // vΘrifier cohΘrence de adr et fil (non vide!)
  655.   if (strnotempty(adr)==0) {
  656.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  657.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
  658.     }
  659.     return -1;    // erreur!
  660.   }
  661.   if (strnotempty(fil)==0) {
  662.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  663.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
  664.     }
  665.     return -1;    // erreur!
  666.   }
  667.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  668.  
  669.   // stats
  670.   opt->state.back_add_stats++;
  671.  
  672.   // rechercher emplacement
  673.   back_clean(opt, cache, back, back_max);
  674.   if ( ( p = back_search(opt, cache, back, back_max) ) >= 0) {
  675.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  676.  
  677.     // clear r
  678.     if (back[p].r.soc!=INVALID_SOCKET) {  /* we never know */
  679.       deletehttp(&back[p].r);
  680.     }
  681.     memset(&(back[p].r), 0, sizeof(htsblk)); 
  682.     back[p].r.soc=INVALID_SOCKET; 
  683.     back[p].r.location=back[p].location_buffer;
  684.  
  685.     // crΘer entrΘe
  686.     strcpybuff(back[p].url_adr,adr);
  687.     strcpybuff(back[p].url_fil,fil);
  688.     strcpybuff(back[p].url_sav,save);
  689.     back[p].pass2_ptr=pass2_ptr;
  690.     // copier referer si besoin
  691.     strcpybuff(back[p].referer_adr,"");
  692.     strcpybuff(back[p].referer_fil,"");
  693.     if ((referer_adr) && (referer_fil)) {       // existe
  694.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  695.         if (referer_adr[0]!='!') {    // non dΘtruit
  696.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  697.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  698.               strcpybuff(back[p].referer_adr,referer_adr);
  699.               strcpybuff(back[p].referer_fil,referer_fil);
  700.             }
  701.           }
  702.         }
  703.       }
  704.     }
  705.     // sav ne sert α rien pour le moment
  706.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  707.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  708.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  709.     back[p].maxfile_html=opt->maxfile_html;
  710.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  711.     back[p].testmode=test;              // mode test?
  712.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  713.       back[p].http11=1;               // autoriser http/1.1
  714.     back[p].head_request=0;
  715.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  716.       back[p].head_request=1;
  717.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  718.       back[p].head_request=2;       // test en get
  719.  
  720.     /* Stop requested - abort backing */
  721.     if (opt->state.stop) {
  722.       back[p].r.statuscode=-1;        // fatal
  723.       strcpybuff(back[p].r.msg,"mirror stopped by user");
  724.       back[p].status=0;  // terminΘ
  725.       if ((opt->debug>0) && (opt->log!=NULL)) {
  726.         fspc(opt->log,"warning"); fprintf(opt->log,"File not added due to mirror cancel: %s%s"LF,adr,fil); test_flush;
  727.       }            
  728.       return 0;
  729.     }
  730.  
  731.     // test "fast header" cache ; that is, tests we did that lead to 3XX/4XX/5XX response codes
  732.     if (cache->cached_tests != NULL) {
  733.       long int ptr = 0;
  734.       if (inthash_read((inthash)cache->cached_tests, concat(adr, fil), (long int*)&ptr)) {    // gotcha
  735.         if (ptr != 0) {
  736.           char* text = (char*) ptr;
  737.           char* lf = strchr(text, '\n');
  738.           int code = 0;
  739.           if (sscanf(text, "%d", &code) == 1) {     // got code
  740.              back[p].r.statuscode=code;
  741.              if (lf != NULL && *lf != '\0') {     // got location ?
  742.                strcpybuff(back[p].r.location, lf + 1);
  743.              }
  744.              return 0;
  745.           }
  746.         }
  747.       }
  748.     }
  749.  
  750.     // tester cache
  751.     if ((strcmp(adr,"file://"))           /* pas fichier */
  752.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  753.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  754.       //if ((!test) && (strcmp(adr,"file://")) 
  755.       //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://")) 
  756. #if HTS_FAST_CACHE
  757.       long int hash_pos;
  758.       int hash_pos_return=0;
  759. #else
  760.       char* a=NULL;
  761. #endif
  762. #if HTS_FAST_CACHE
  763.       if (cache->hashtable) { 
  764. #else
  765.       if (cache->use) { 
  766. #endif
  767.         char BIGSTK buff[HTS_URLMAXSIZE*4];
  768. #if HTS_FAST_CACHE
  769.         strcpybuff(buff,adr); strcatbuff(buff,fil);
  770.         hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  771. #else
  772.         buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  773.         a=strstr(cache->use,buff);
  774. #endif
  775.         
  776.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  777. #if HTS_FAST_CACHE
  778.         if (hash_pos_return) {
  779. #else
  780.         if (a) {
  781. #endif
  782.           if (!test) {      // non mode test
  783. #if HTS_FAST_CACHE
  784.             int pos=hash_pos;
  785. #else
  786.             int pos=-1;
  787.             a+=strlen(buff);
  788.             sscanf(a,"%d",&pos);    // lire position
  789. #endif
  790.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  791.               if (fsize(fconv(save)) <= 0) {  // fichier existe pas ou est vide!
  792.                 int found=0;
  793.  
  794.                 /* It is possible that the file has been moved due to changes in build structure */
  795.                 {
  796.                   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  797.                   previous_save[0] = '\0';
  798.                   back[p].r = cache_readex(opt, cache, adr, fil, NULL, back[p].location_buffer, previous_save, 0);
  799.                   if (previous_save[0] != '\0' && fexist(fconv(previous_save))) {
  800.                     rename(fconv(previous_save), fconv(save));
  801.                     if (fexist(fconv(save))) {
  802.                       found = 1;
  803.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  804.                         fspc(opt->log,"debug"); fprintf(opt->log,"File '%s' has been renamed since last mirror to '%s' ; applying changes"LF, previous_save, save); test_flush;
  805.                       }
  806.                     } else {
  807.                       if ((opt->debug>0) && (opt->log!=NULL)) {
  808.                         fspc(opt->log,"error"); fprintf(opt->log,"Could not rename '%s' to '%s' ; will have to retransfer it"LF, previous_save, save); test_flush;
  809.                       }
  810.                     }
  811.                   }
  812.                 }
  813.                 
  814.                 if (!found) {
  815. #if HTS_FAST_CACHE
  816.                   hash_pos_return=0;
  817. #else
  818.                   a=NULL;    
  819. #endif
  820.                   // dΘvalider car non prΘsent sur disque dans structure originale!!!
  821.                   // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  822.                   // en Ωtre s√r
  823.                   if (opt->norecatch) {              // tester norecatch
  824.                     if (!fexist(fconv(save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  825.                       FILE* fp=fopen(fconv(save),"wb");
  826.                       if (fp) fclose(fp);
  827.                       if (opt->log!=NULL) {
  828.                         fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  829.                       }
  830.                     }
  831.                   }
  832.                 }
  833.               }
  834.             }
  835.           }
  836.         }
  837.         //
  838.       } else
  839. #if HTS_FAST_CACHE
  840.         hash_pos_return=0;
  841. #else
  842.         a=NULL;
  843. #endif
  844.  
  845.       // Existe pas en cache, ou bien pas de cache prΘsent
  846. #if HTS_FAST_CACHE
  847.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  848. #else
  849.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  850. #endif
  851.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  852.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302...
  853.           // lire dans le cache
  854.           if (!test)
  855.             back[p].r = cache_read(opt,cache,adr,fil,save, back[p].location_buffer);
  856.           else
  857.             back[p].r = cache_read(opt,cache,adr,fil,NULL, back[p].location_buffer);  // charger en tΩte uniquement du cache
  858.  
  859.           /* ensure correct location buffer set */
  860.           back[p].r.location=back[p].location_buffer;
  861.  
  862.           /* Interdiction taille par le wizard? --> dΘtruire */
  863.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  864.             if (!back_checksize(opt,&back[p],0)) {
  865.               back[p].status=0;  // FINI
  866.               back[p].r.statuscode=-1;
  867.               if (!back[p].testmode)
  868.                 strcpybuff(back[p].r.msg,"Cached file skipped (too big)");
  869.               else
  870.                 strcpybuff(back[p].r.msg,"Test: Cached file skipped  (too big)");
  871.               return 0;
  872.             }
  873.           }
  874.  
  875.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  876.             if ((opt->debug>0) && (opt->log!=NULL)) {
  877.               if (!test) {
  878.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  879.               } else {
  880.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  881.               }
  882.             }
  883.             back[p].r.notmodified=1;    // fichier non modifiΘ
  884.             back[p].status=0;  // OK prΩt
  885.  
  886.             // finalize transfer
  887.             if (!test) {
  888.               if (back[p].r.statuscode>0) {
  889.                 back_finalize(opt,cache,back,p);
  890.               }
  891.             }
  892.  
  893.             return 0;
  894.           } else {  // erreur
  895.             // effacer r
  896.             memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  897.             // et continuer (chercher le fichier)
  898.           }
  899.           
  900.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  901.           htsblk r;
  902.           cache_header(opt,cache,adr,fil,&r);
  903.  
  904.           /* Interdiction taille par le wizard? */
  905.           {
  906.             LLint save_totalsize=back[p].r.totalsize;
  907.             back[p].r.totalsize=r.totalsize;
  908.             if (!back_checksize(opt,&back[p],1)) {
  909.               r.statuscode = -1;
  910.               //
  911.               back[p].status=0;  // FINI
  912.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  913.               if (!back[p].testmode)
  914.                 strcpybuff(back[p].r.msg,"File too big");
  915.               else
  916.                 strcpybuff(back[p].r.msg,"Test: File too big");
  917.               return 0;
  918.             }
  919.             back[p].r.totalsize=save_totalsize;
  920.           }
  921.           
  922.           if (r.statuscode != -1) {
  923.             if (r.statuscode==200) {     // uniquement des 200 (OK)
  924.               if (strnotempty(r.etag)) {  // ETag (RFC2616)
  925.                 /*
  926.                 - If both an entity tag and a Last-Modified value have been
  927.                 provided by the origin server, SHOULD use both validators in
  928.                 cache-conditional requests. This allows both HTTP/1.0 and
  929.                 HTTP/1.1 caches to respond appropriately.
  930.                 */
  931.                 if (strnotempty(r.lastmodified))
  932.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r.etag,r.lastmodified);
  933.                 else
  934.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r.etag);
  935.               }
  936.               else if (strnotempty(r.lastmodified))
  937.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r.lastmodified);
  938.               else if (strnotempty(cache->lastmodified))
  939.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  940.               
  941.               /* this is an update of a file */
  942.               if (strnotempty(back[p].send_too))
  943.                 back[p].is_update=1;
  944.               back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  945.               
  946.             }
  947.           }
  948. #if DEBUGCA
  949.           printf("..is modified test %s\n",back[p].send_too);
  950. #endif
  951.         } 
  952.         // Okay, pas trouvΘ dans le cache
  953.         // Et si le fichier existe sur disque?
  954.         // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
  955.       } else {
  956.         if (fexist(save)) {    // fichier existe? aghl!
  957.           LLint sz=fsize(save);
  958.           // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  959.           // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  960.           // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  961.           // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  962.           if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  963.             if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  964.               char lastmodified[256];
  965.               get_filetime_rfc822(save, lastmodified);
  966.               if (strnotempty(lastmodified)) {     /* pas de If-.. possible */
  967. #if DEBUGCA
  968.                 printf("..if unmodified since %s size "LLintP"\n", lastmodified, (LLint)sz);
  969. #endif
  970.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  971.                   fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  972.                 }
  973.                 
  974.                 /* impossible - don't have etag or date
  975.                 if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  976.                 sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  977.                 back[p].http11=1;    // En tΩte 1.1
  978.                 } else if (strnotempty(back[p].r.lastmodified)) {
  979.                 sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  980.                 back[p].http11=1;    // En tΩte 1.1
  981.                 } else 
  982.                 */
  983.                 if (strlen(lastmodified)) {
  984.                   sprintf(back[p].send_too,
  985.                     "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  986.                     , lastmodified, (LLint)sz);
  987.                   back[p].http11=1;    // En tΩte 1.1
  988.                   back[p].range_req_size=sz;
  989.                   back[p].r.req.range_used=1;
  990.                   back[p].r.req.nocompression=1;
  991.                 } else {
  992.                   if ((opt->debug>0) && (opt->log!=NULL)) {
  993.                     fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  994.                   }
  995.                 }
  996.                 
  997.               } else { 
  998.                 if ((opt->debug>0) && (opt->errlog!=NULL)) {
  999.                   fspc(opt->errlog,"warning");
  1000.                   /*
  1001.                   if (opt->http10)
  1002.                   fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  1003.                   else
  1004.                   */
  1005.                   fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  1006.                   test_flush;
  1007.                 }
  1008.                 /* Sinon requΩte normale... */
  1009.                 back[p].http11=0;
  1010.               }
  1011.             } else if (opt->norecatch) {              // tester norecatch
  1012.               filenote(save,NULL);       // ne pas purger tout de mΩme
  1013.               back[p].status=0;  // OK prΩt
  1014.               back[p].r.statuscode=-1;  // erreur
  1015.               strcpybuff(back[p].r.msg,"Null-size file not recaught");
  1016.               return 0;
  1017.             }
  1018.           } else {
  1019.             if ((opt->debug>0) && (opt->errlog!=NULL)) {
  1020.               fspc(opt->errlog,"warning");
  1021.               fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  1022.               test_flush;
  1023.             }
  1024.             /* Sinon requΩte normale... */
  1025.             back[p].http11=0;
  1026.           }
  1027.         }
  1028.       }
  1029.     }
  1030.  
  1031.  
  1032.     {
  1033.       ///htsblk r;   non directement dans la structure-rΘponse!
  1034.       T_SOC soc;
  1035.       
  1036.       // ouvrir liaison, envoyer requΦte
  1037.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  1038.       memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  1039.       // recopier proxy
  1040.       memcpy(&(back[p].r.req.proxy), &opt->proxy, sizeof(opt->proxy));
  1041.       // et user-agent
  1042.       strcpybuff(back[p].r.req.user_agent,opt->user_agent);
  1043.       strcpybuff(back[p].r.req.referer,opt->referer);
  1044.       strcpybuff(back[p].r.req.from,opt->from);
  1045.       strcpybuff(back[p].r.req.lang_iso,opt->lang_iso);
  1046.       back[p].r.req.user_agent_send=opt->user_agent_send;
  1047.       // et http11
  1048.       back[p].r.req.http11=back[p].http11;
  1049.       back[p].r.req.nocompression=opt->nocompression;
  1050.       back[p].r.req.nokeepalive=opt->nokeepalive;
  1051.  
  1052.       // mode ftp, court-circuit!
  1053.       if (strfield(back[p].url_adr,"ftp://")) {
  1054.         if (back[p].testmode) {
  1055.           if ((opt->debug>1) && (opt->errlog!=NULL)) {
  1056.             fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
  1057.           }
  1058.           return -1;    // erreur pas de test permis
  1059.         }
  1060.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  1061.           back[p].status=1000;   // connexion ftp
  1062. #if USE_BEGINTHREAD
  1063.           launch_ftp(&(back[p]));
  1064. #else
  1065.           {
  1066.             char nid[32];
  1067.             sprintf(nid,"htsftp%d-in_progress.lock",p);
  1068.             strcpybuff(back[p].location_buffer,fconcat(opt->path_log,nid));
  1069.           }
  1070.           launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
  1071. #endif
  1072.           return 0;
  1073.         }
  1074.       }
  1075. #if HTS_USEOPENSSL
  1076.       else if (SSL_is_available && strfield(back[p].url_adr,"https://")) {        // let's rock
  1077.         back[p].r.ssl = 1;
  1078.         // back[p].r.ssl_soc = NULL;
  1079.         back[p].r.ssl_con = NULL;
  1080.       }
  1081. #endif
  1082.       
  1083.       if (!back_trylive(opt, cache, back, back_max, p)) {
  1084. #if HTS_XGETHOST
  1085. #if HDEBUG
  1086.         printf("back_solve..\n");
  1087. #endif
  1088.         back[p].status=101;    // tentative de rΘsolution du nom de host
  1089.         soc=INVALID_SOCKET;    // pas encore ouverte
  1090.         back_solve(&back[p]);  // prΘparer
  1091.         if (host_wait(&back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  1092. #if HDEBUG
  1093.           printf("ok, dns cache ready..\n");
  1094. #endif
  1095.           soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  1096.           if (soc==INVALID_SOCKET) {
  1097.             back[p].status=0;  // fini, erreur
  1098.           }
  1099.         }
  1100.         //
  1101. #else
  1102.         //
  1103. #if CNXDEBUG
  1104.         printf("XFopen..\n");
  1105. #endif
  1106.         
  1107.         if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  1108. #if HTS_XCONN
  1109.           soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  1110. #else
  1111.         soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  1112. #endif
  1113.         else
  1114. #if HTS_XCONN
  1115.           soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  1116. #else
  1117.         soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  1118. #endif
  1119. #endif
  1120.       } else {
  1121.         soc = back[p].r.soc;
  1122.  
  1123.         if ((opt->debug>1) && (opt->log!=NULL)) {
  1124.           fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): successfully linked #%d (for %s%s)"LF, 
  1125.             back[p].r.debugid,
  1126.             back[p].url_adr, back[p].url_fil); test_flush;
  1127.         }
  1128.       }
  1129.       
  1130.       if (opt->timeout>0) {    // gestion du opt->timeout
  1131.         back[p].timeout=opt->timeout;
  1132.         back[p].timeout_refresh=time_local();
  1133.       } else {
  1134.         back[p].timeout=-1;    // pas de gestion (default)
  1135.       }
  1136.       
  1137.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  1138.         back[p].rateout=opt->rateout;
  1139.         back[p].rateout_time=time_local();
  1140.       } else {
  1141.         back[p].rateout=-1;    // pas de gestion (default)
  1142.       }
  1143.  
  1144.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  1145.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  1146.       //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
  1147.  
  1148. #if CNXDEBUG
  1149. printf("Xfopen ok, poll..\n");
  1150. #endif
  1151.  
  1152. #if HTS_XGETHOST
  1153.     if (soc!=INVALID_SOCKET)
  1154.       if (back[p].status==101) {  // pas d'erreur
  1155.         if (!back[p].r.is_file)
  1156.           back[p].status=100;   // connexion en cours
  1157.         else
  1158.           back[p].status=1;     // fichier
  1159.       }
  1160.  
  1161. #else
  1162.       if (soc==INVALID_SOCKET) { // erreur socket
  1163.         back[p].status=0;    // FINI
  1164.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  1165.         back[p].r.soc=INVALID_SOCKET;
  1166.       } else {
  1167.         if (!back[p].r.is_file)
  1168. #if HTS_XCONN
  1169.           back[p].status=100;   // connexion en cours
  1170. #else
  1171.           back[p].status=99;    // chargement en tΩte en cours
  1172. #endif
  1173.         else
  1174.           back[p].status=1;     // chargement fichier
  1175. #if BDEBUG==1
  1176.         printf("..loading header\n");
  1177. #endif
  1178.       }
  1179. #endif
  1180.       
  1181.     }
  1182.  
  1183.  
  1184.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  1185.     // le lien est considΘrΘ comme traitΘ
  1186.     //if (back[p].soc<0)  // erreur
  1187.     //  return -1;
  1188.  
  1189.     return 0;
  1190.   } else {
  1191.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  1192.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
  1193.     }
  1194.     return -1;    // plus de place
  1195.   }
  1196. }
  1197.  
  1198.  
  1199.  
  1200. #if HTS_XGETHOST
  1201. #if USE_BEGINTHREAD
  1202. // lancement multithread du robot
  1203. PTHREAD_TYPE PTHREAD_TYPE_FNC Hostlookup(void* iadr_p) {
  1204.   char iadr[256];
  1205.   t_dnscache* cache=_hts_cache();  // adresse du cache
  1206.   t_hostent* hp;
  1207.   int error_found=0;
  1208.  
  1209.   // recopier (aprΦs id:pass)
  1210. #if DEBUGDNS 
  1211.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  1212. #endif
  1213.   strcpybuff(iadr,jump_identification(iadr_p));
  1214.   // couper Θventuel :
  1215.   {
  1216.     char *a;
  1217.     if ( (a=jump_toport(iadr)) )
  1218.       *a='\0';          // get rid of it
  1219.   }
  1220.   freet(iadr_p);
  1221.  
  1222.   // attendre que le cache dns soit prΩt
  1223.   while(_hts_lockdns(-1));  // attendre libΘration
  1224.   _hts_lockdns(1);          // locker
  1225.   while(cache->n) {
  1226.     if (strcmp(cache->iadr,iadr)==0) {
  1227.       error_found=1;
  1228.     }
  1229.     cache=cache->n;    // calculer queue
  1230.   }
  1231.   if (strcmp(cache->iadr,iadr)==0) {
  1232.     error_found=1;
  1233.   }
  1234.  
  1235.   if (!error_found) {
  1236.     // en gros copie de hts_gethostbyname sans le return
  1237.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  1238.     if (cache->n!=NULL) {
  1239.       t_fullhostent fullhostent_buffer;
  1240.       strcpybuff(cache->n->iadr,iadr);
  1241.       cache->n->host_length=0;        /* pour le moment rien */
  1242.       cache->n->n=NULL;
  1243.       _hts_lockdns(0);          // dΘlocker
  1244.       
  1245.       /* resolve */
  1246. #if DEBUGDNS 
  1247.       printf("gethostbyname() in progress for %s\n",iadr);
  1248. #endif
  1249.       cache->n->host_length=-1;
  1250.       memset(cache->n->host_addr, 0, sizeof(cache->n->host_addr));
  1251.       hp=vxgethostbyname(iadr, &fullhostent_buffer);
  1252.       if (hp!=NULL) {
  1253.         memcpy(cache->n->host_addr, hp->h_addr, hp->h_length);
  1254.         cache->n->host_length = hp->h_length;
  1255.       }
  1256.     } else 
  1257.     _hts_lockdns(0);          // dΘlocker
  1258.   } else {
  1259. #if DEBUGDNS 
  1260.     printf("aborting resolv for %s (found)\n",iadr);
  1261. #endif
  1262.     _hts_lockdns(0);          // dΘlocker
  1263.   }
  1264.   // fin de copie de hts_gethostbyname
  1265.  
  1266. #if DEBUGDNS 
  1267.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  1268. #endif
  1269.  
  1270.   return PTHREAD_RETURN;     /* _endthread implied  */
  1271. }
  1272. #endif
  1273.  
  1274. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  1275. // si c'est un fichier, la rΘsolution est immΘdiate
  1276. // idem pour ftp://
  1277. void back_solve(lien_back* back) {
  1278.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1279.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  1280.     char* a;
  1281.     if (!(back->r.req.proxy.active))
  1282.       a=back->url_adr;
  1283.     else
  1284.       a=back->r.req.proxy.name;
  1285.     a = jump_protocol(a);
  1286.     if (!hts_dnstest(a)) {   // non encore testΘ!..
  1287.       // inscire en thread
  1288. #if HTS_WIN
  1289.       // Windows
  1290. #if USE_BEGINTHREAD
  1291.       {
  1292.         char* p = calloct(strlen(a)+2,1);
  1293.         if (p) {
  1294.           strcpybuff(p,a);
  1295.           (void)hts_newthread( Hostlookup , 0, p );
  1296.         }
  1297.       }
  1298. #else
  1299.       /*t_hostent* h=*/
  1300.       /*hts_gethostbyname(a);*/  // calcul
  1301. #endif
  1302. #else
  1303. #if USE_BEGINTHREAD
  1304.         char* p = calloct(strlen(a)+2,1);
  1305.         if (p) {
  1306.           strcpybuff(p,a);
  1307.           (void)hts_newthread( Hostlookup , 0, p );
  1308.         }
  1309. #else
  1310.       // Sous Unix, le gethostbyname() est bloquant..
  1311.       /*t_hostent* h=*/
  1312.       /*hts_gethostbyname(a);*/  // calcul
  1313. #endif
  1314. #endif
  1315.     }
  1316.   }
  1317. }
  1318.  
  1319. // dΘtermine si le host a pu Ωtre rΘsolu
  1320. int host_wait(lien_back* back) {
  1321.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1322.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  1323.     if (!(back->r.req.proxy.active)) {
  1324.       return (hts_dnstest(back->url_adr));
  1325.     } else {
  1326.       return (hts_dnstest(back->r.req.proxy.name));      
  1327.     }
  1328.   } else return 1;    // prΩt, fichier local
  1329. }
  1330. #endif
  1331.  
  1332.  
  1333. // Θlimine les fichiers non html en backing (anticipation)
  1334. // cleanup non-html files in backing to save backing space
  1335. // and allow faster "save in cache" operation
  1336. // also cleanup keep-alive sockets and ensure that not too many sockets are being opened
  1337. void back_clean(httrackp* opt,cache_back* cache,lien_back* back,int back_max) {
  1338. #if HTS_ANALYSTE
  1339.   int oneMore = ( (_hts_in_html_parsing == 2 && opt->maxsoc >= 2) || (_hts_in_html_parsing == 1 && opt->maxsoc >= 4) ) ? 1 : 0;  // testing links
  1340. #endif
  1341.   int i;
  1342.   for(i=0;i<back_max;i++) {
  1343.     if (back[i].status == 0) {                                   // ready
  1344.       /* Check autoclean */
  1345.       if (!back[i].testmode) {                                   // not test mode
  1346.         if (strnotempty(back[i].url_sav)) {                      // filename exists
  1347.           if (back[i].r.statuscode==200) {                   // HTTP "OK"
  1348.             if (back[i].r.size>0) {                              // size>0
  1349.               if (back[i].r.is_write                                // not in memory (on disk, ready)
  1350.                 && !is_hypertext_mime(back[i].r.contenttype, back[i].url_fil)        // not HTML/hypertext
  1351.                 && !may_be_hypertext_mime(back[i].r.contenttype, back[i].url_fil)    // may NOT be parseable mime type
  1352.                 ) {
  1353.                 if (back[i].pass2_ptr) {
  1354.                   // finalize
  1355.                   // // back_finalize(opt,cache,back,i);
  1356.                   // stats
  1357.                   //HTS_STAT.stat_bytes+=back[i].r.size;
  1358.                   //HTS_STAT.stat_files++;
  1359.                   //if ( (!back[i].r.notmodified) && (opt->is_update) ) { 
  1360.                   //  HTS_STAT.stat_updated_files++;       // page modifiΘe
  1361.                   //}
  1362.                   //xxxcache_mayadd(opt,cache,&back[i].r,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1363.                   usercommand(opt, 0, NULL, back[i].url_sav, back[i].url_adr, back[i].url_fil);
  1364.                   *back[i].pass2_ptr=-1;  // Done!
  1365.                   if ((opt->debug>0) && (opt->log!=NULL)) {
  1366.                     fspc(opt->log,"info"); fprintf(opt->log,"File successfully written in background: %s"LF,back[i].url_sav); test_flush;
  1367.                   }
  1368.                   back_maydelete(opt,cache,back,i);    // May delete backing entry
  1369.                 }
  1370.               } else {
  1371.                 if (!back[i].finalized) {
  1372.                   if (1) {
  1373.                     /* Ensure deleted or recycled socket */
  1374.                     /* BUT DO NOT YET WIPE back[i].r.adr */
  1375.                     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  1376.                       fspc(opt->log,"debug"); fprintf(opt->log,"file %s%s validated (cached, left in memory)"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1377.                     }
  1378.                     back_maydeletehttp(opt, cache, back, back_max, i);
  1379.                   } else {
  1380.                   /*
  1381.                   NOT YET HANDLED CORRECTLY (READ IN NEW CACHE TO DO)
  1382.                     */
  1383.                     /* Lock the entry but do not keep the html data in memory (in cache) */
  1384.                     if (opt->cache) {
  1385.                       htsblk r;
  1386.                       
  1387.                       /* Ensure deleted or recycled socket */
  1388.                       back_maydeletehttp(opt, cache, back, back_max, i);
  1389.                       assertf(back[i].r.soc == INVALID_SOCKET);
  1390.                       
  1391.                       /* Check header */
  1392.                       cache_header(opt,cache,back[i].url_adr,back[i].url_fil,&r);
  1393.                       if (r.statuscode == 200) {
  1394.                         if (back[i].r.soc == INVALID_SOCKET) {
  1395.                           /* Delete buffer and sockets */
  1396.                           deleteaddr(&back[i].r);
  1397.                           deletehttp(&back[i].r);
  1398.                           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  1399.                             fspc(opt->log,"debug"); fprintf(opt->log,"file %s%s temporarily left in cache to spare memory"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1400.                           }
  1401.                         }
  1402.                       } else {
  1403.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  1404.                           fspc(opt->log,"warning"); fprintf(opt->log,"Unexpected html cache lookup error during back clean"LF); test_flush;
  1405.                         }            
  1406.                       }
  1407.                       // xxc xxc
  1408.                     }
  1409.                   }
  1410.                 }
  1411.               }
  1412.             }
  1413.           }
  1414.         }
  1415.       }
  1416.     } else if (back[i].status == -103) {                         // waiting (keep-alive)
  1417.       if (
  1418.         ! back[i].r.keep_alive
  1419.         || back[i].r.soc == INVALID_SOCKET
  1420.         || back[i].r.keep_alive_max < 1
  1421.         || time_local() >= back[i].ka_time_start + back[i].r.keep_alive_t
  1422.         ) {
  1423.         if ((opt->debug>0) && (opt->log!=NULL)) {
  1424.             fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): live socket closed #%d (%s)"LF, 
  1425.             back[i].r.debugid,
  1426.             back[i].url_adr);
  1427.             test_flush;
  1428.         }
  1429.         back_delete(opt,cache,back, i);    // delete backing entry
  1430.       }
  1431.     }
  1432.   }
  1433.   /* switch connections to live ones */
  1434.   for(i=0;i<back_max;i++) {
  1435.     if (back[i].status == 0) {                                   // ready
  1436.       if (back[i].r.soc != INVALID_SOCKET) {
  1437.         back_maydeletehttp(opt,cache,back, back_max, i);
  1438.       }
  1439.       
  1440.     }
  1441.   }
  1442.   /* delete sockets if too many keep-alive'd sockets in background */
  1443.   if (opt->maxsoc > 0) {
  1444.     int max = opt->maxsoc + oneMore;
  1445.     int curr = back_nsoc_overall(back, back_max);
  1446.     if (curr > max) {
  1447.       if ((opt->debug>1) && (opt->log!=NULL)) {
  1448.         fspc(opt->log,"debug"); fprintf(opt->log,"(Keep-Alive): deleting #%d sockets"LF, 
  1449.           curr - max); test_flush;
  1450.       }
  1451.     }
  1452.     for(i = 0 ; i < back_max && curr > max ; i++) {
  1453.       if (back[i].status == -103) {
  1454.         back_delete(opt,cache,back, i);    // delete backing entry
  1455.         curr--;
  1456.       }
  1457.     }
  1458.   }
  1459. }
  1460.  
  1461.  
  1462. // attente (gestion des buffers des sockets)
  1463. void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,TStamp stat_timestart) {
  1464.   unsigned int i_mod;
  1465.   T_SOC nfds=INVALID_SOCKET;
  1466.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  1467.   int nsockets;     // nbre sockets
  1468.   LLint max_read_bytes;  // max bytes read per sockets
  1469.   struct timeval tv;
  1470.   int do_wait=0;
  1471.   int gestion_timeout=0;
  1472.   int busy_recv=0;     // pas de donnΘes pour le moment   
  1473.   int busy_state=0;    // pas de connexions
  1474.   int max_loop;  // nombre de boucles max α parcourir..
  1475. #if HTS_ANALYSTE
  1476.   int max_loop_chk=0;
  1477. #endif
  1478.   unsigned int mod_random = (unsigned int) ( time_local() + HTS_STAT.HTS_TOTAL_RECV );
  1479.  
  1480.   // max. number of loops
  1481.   max_loop=8;
  1482.  
  1483. #if 1
  1484.   // Cleanup the stack to save space!
  1485.   back_clean(opt,cache,back,back_max);
  1486. #endif
  1487.  
  1488.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  1489.   do_wait=0;
  1490.   gestion_timeout=0;
  1491.   do {
  1492.     int max_c;
  1493.     busy_state=busy_recv=0;
  1494.  
  1495. #if 0
  1496.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  1497. #endif
  1498.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  1499.     FD_ZERO(&fds);
  1500.     FD_ZERO(&fds_c);
  1501.     FD_ZERO(&fds_e);
  1502.     nsockets=0;
  1503.     max_read_bytes=TAILLE_BUFFER;     // maximum bytes that can be read
  1504.     nfds=INVALID_SOCKET;
  1505.  
  1506.     max_c=1;
  1507.     for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  1508.     // for(i=0;i<back_max;i++) {
  1509.         unsigned int i = ( i_mod + mod_random ) % ( back_max );
  1510.  
  1511.       // en cas de gestion du connect prΘemptif
  1512. #if HTS_XCONN
  1513.       if (back[i].status==100) {      // connexion
  1514.         do_wait=1;
  1515.  
  1516.         // noter socket write
  1517.         FD_SET(back[i].r.soc,&fds_c);
  1518.         
  1519.         // noter socket erreur
  1520.         FD_SET(back[i].r.soc,&fds_e);
  1521.  
  1522.         // calculer max
  1523.         if (max_c) {
  1524.           max_c=0;
  1525.           nfds=back[i].r.soc;
  1526.         } else if (back[i].r.soc>nfds) {
  1527.           // ID socket la plus ΘlevΘe
  1528.           nfds=back[i].r.soc;
  1529.         }
  1530.         
  1531.       } else
  1532. #endif
  1533. #if HTS_XGETHOST
  1534.       if (back[i].status==101) {      // attente
  1535.         // rien α faire..
  1536.       } else
  1537. #endif
  1538.       // poll pour la lecture sur les sockets
  1539.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  1540.             
  1541. #if BDEBUG==1
  1542.         //printf("....socket in progress: %d\n",back[i].r.soc);
  1543. #endif
  1544.         // non local et non ftp
  1545.         if (!back[i].r.is_file) {
  1546.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  1547.           
  1548.           // vΘrification de sΘcuritΘ
  1549.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1550.             do_wait=1;
  1551.             
  1552.             // noter socket read
  1553.             FD_SET(back[i].r.soc,&fds);
  1554.             
  1555.             // noter socket error
  1556.             FD_SET(back[i].r.soc,&fds_e);
  1557.             
  1558.             // incrΘmenter nombre de sockets
  1559.             nsockets++;
  1560.  
  1561.             // calculer max
  1562.             if (max_c) {
  1563.               max_c=0;
  1564.               nfds=back[i].r.soc;
  1565.             } else if (back[i].r.soc>nfds) {
  1566.               // ID socket la plus ΘlevΘe
  1567.               nfds=back[i].r.soc;
  1568.             }
  1569.           } else {
  1570.             back[i].r.statuscode=-4;
  1571.             if (back[i].status==100)
  1572.               strcpybuff(back[i].r.msg,"Connect Error");
  1573.             else
  1574.               strcpybuff(back[i].r.msg,"Receive Error");
  1575.             back[i].status=0;  // terminΘ
  1576.             if ((opt->debug>0) && (opt->log!=NULL)) {
  1577.               fspc(opt->log,"warning"); fprintf(opt->log,"Unexpected socket error during pre-loop"LF); test_flush;
  1578.             }            
  1579.           }
  1580. #if WIDE_DEBUG
  1581.           else {
  1582.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  1583.           }
  1584. #endif
  1585.           
  1586.         }
  1587.         
  1588.       }
  1589.     }    
  1590.     nfds++;
  1591.     
  1592.     if (do_wait) {  // attendre
  1593.       // temps d'attente max: 2.5 seconde
  1594.       tv.tv_sec=HTS_SOCK_SEC;
  1595.       tv.tv_usec=HTS_SOCK_MS;
  1596.       
  1597. #if BDEBUG==1
  1598.       printf("..select\n");
  1599. #endif
  1600.       
  1601.       // poller les sockets-attention au noyau sous Unix..
  1602. #if HTS_WIDE_DEBUG    
  1603.       DEBUG_W("select\n");
  1604. #endif
  1605.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  1606. #if HTS_WIDE_DEBUG    
  1607.       DEBUG_W("select done\n");
  1608. #endif      
  1609.     }
  1610.     
  1611.     // maximum data which can be received for a socket, if limited
  1612.     if (nsockets) {
  1613.       if (opt->maxrate>0) {
  1614.         max_read_bytes = ( check_downloadable_bytes(opt->maxrate) / nsockets );
  1615.         if (max_read_bytes > TAILLE_BUFFER) {
  1616.           /* limit size */
  1617.           max_read_bytes = TAILLE_BUFFER;
  1618.         } else if (max_read_bytes < TAILLE_BUFFER) {
  1619.           /* a small pause */
  1620.           Sleep(10);
  1621.         }
  1622.       }
  1623.     }
  1624.     if (!max_read_bytes)
  1625.       busy_recv=0;
  1626.     
  1627.     // recevoir les donnΘes arrivΘes
  1628.     for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  1629.     // for(i=0;i<back_max;i++) {
  1630.         unsigned int i = ( i_mod + mod_random ) % ( back_max );     
  1631.       if (back[i].status>0) {
  1632.         if (!back[i].r.is_file) {  // not file..
  1633.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1634.             int err=FD_ISSET(back[i].r.soc,&fds_e);
  1635.             if (err) {
  1636.               if (back[i].r.soc!=INVALID_SOCKET) {
  1637. #if HTS_DEBUG_CLOSESOCK
  1638.                 DEBUG_W("back_wait: deletehttp\n");
  1639. #endif
  1640.                 deletehttp(&back[i].r);
  1641.               }
  1642.               back[i].r.soc=INVALID_SOCKET;
  1643.               back[i].r.statuscode=-4;
  1644.               if (back[i].status==100)
  1645.                 strcpybuff(back[i].r.msg,"Connect Error");
  1646.               else
  1647.                 strcpybuff(back[i].r.msg,"Receive Error");
  1648.               if (back[i].status == -103) {     /* Keep-alive socket */
  1649.                 back_delete(opt,cache,back, i);
  1650.               } else {
  1651.                 back[i].status=0;  // terminΘ
  1652.               }
  1653.             }
  1654.           }
  1655.         }
  1656.       }
  1657.       
  1658.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  1659.       if (back[i].status==100) {   // attendre connect
  1660.         int dispo=0;
  1661.         // vΘrifier l'existance de timeout-check
  1662.         if (!gestion_timeout)
  1663.           if (back[i].timeout>0)
  1664.             gestion_timeout=1;
  1665.           
  1666.           // connectΘ?
  1667.           dispo=FD_ISSET(back[i].r.soc,&fds_c);
  1668.           if (dispo) {    // ok connected!!
  1669.             busy_state=1;
  1670.             
  1671. #if HTS_USEOPENSSL
  1672.             /* SSL mode */
  1673.             if (SSL_is_available && back[i].r.ssl) {
  1674.               // handshake not yet launched
  1675.               if (!back[i].r.ssl_con) {
  1676.                 SSL_CTX_set_options(openssl_ctx, SSL_OP_ALL);
  1677.                 // new session
  1678.                 back[i].r.ssl_con = SSL_new(openssl_ctx);
  1679.                 if (back[i].r.ssl_con) {
  1680.                   SSL_clear(back[i].r.ssl_con);
  1681.                   if (SSL_set_fd(back[i].r.ssl_con, back[i].r.soc) == 1) {
  1682.                     SSL_set_connect_state(back[i].r.ssl_con);
  1683.                     back[i].status = 102;         /* handshake wait */
  1684.                   } else
  1685.                     back[i].r.statuscode=-6;
  1686.                 } else
  1687.                   back[i].r.statuscode=-6;
  1688.               }
  1689.               /* Error */
  1690.               if (back[i].r.statuscode == -6) {
  1691.                 strcpybuff(back[i].r.msg, "bad SSL/TLS handshake");
  1692.                 deletehttp(&back[i].r);
  1693.                 back[i].r.soc=INVALID_SOCKET;
  1694.                 back[i].r.statuscode=-5;
  1695.                 back[i].status=0;
  1696.               }
  1697.             }
  1698.             
  1699. #endif
  1700.  
  1701. #if BDEBUG==1
  1702.           printf("..connect ok on socket %d\n",back[i].r.soc);
  1703. #endif
  1704.           
  1705.           if ((back[i].r.soc != INVALID_SOCKET) && (back[i].status==100)) {
  1706.             /* limit nb. connections/seconds to avoid server overload */
  1707.             /*if (opt->maxconn>0) {
  1708.               Sleep(1000/opt->maxconn);
  1709.             }*/
  1710.             
  1711.             back[i].ka_time_start=time_local();
  1712.             if (back[i].timeout>0) {    // refresh timeout si besoin est
  1713.               back[i].timeout_refresh=back[i].ka_time_start;
  1714.             }
  1715.             if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1716.               back[i].rateout_time=back[i].ka_time_start;
  1717.             }
  1718.             // envoyer header
  1719.             //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  1720.             HTS_STAT.stat_nrequests++;
  1721.             if (!back[i].head_request)
  1722.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1723.             else if (back[i].head_request==2)  // test en GET!
  1724.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1725.             else        // test!
  1726.               http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1727.             back[i].status=99;  // attendre en tΩte maintenant
  1728.           }
  1729.         }
  1730.         
  1731.         // attente gethostbyname
  1732.       }
  1733. #if HTS_USEOPENSSL
  1734.       else if (SSL_is_available && back[i].status==102) {   // wait for SSL handshake
  1735.         /* SSL mode */
  1736.         if (back[i].r.ssl) {
  1737.           int conn_code;
  1738.           if ((conn_code = SSL_connect(back[i].r.ssl_con)) <= 0) {
  1739.             /* non blocking I/O, will retry */
  1740.             int err_code = SSL_get_error(back[i].r.ssl_con, conn_code);
  1741.             if (
  1742.               (err_code != SSL_ERROR_WANT_READ)
  1743.               &&
  1744.               (err_code != SSL_ERROR_WANT_WRITE)
  1745.               ) {
  1746.               char tmp[256];
  1747.               tmp[0]='\0';
  1748.               ERR_error_string(err_code, tmp);
  1749.               back[i].r.msg[0]='\0';
  1750.               strncatbuff(back[i].r.msg, tmp, sizeof(back[i].r.msg) - 2);
  1751.               if (!strnotempty(back[i].r.msg)) {
  1752.                 sprintf(back[i].r.msg, "SSL/TLS error %d", err_code);
  1753.               }
  1754.               deletehttp(&back[i].r);
  1755.               back[i].r.soc=INVALID_SOCKET;
  1756.               back[i].r.statuscode=-5;
  1757.               back[i].status=0;
  1758.             }
  1759.           } else {        /* got it! */
  1760.             back[i].status=100;       // back to waitconnect
  1761.           }
  1762.         } else {
  1763.           strcpybuff(back[i].r.msg, "unexpected SSL/TLS error");
  1764.           deletehttp(&back[i].r);
  1765.           back[i].r.soc=INVALID_SOCKET;
  1766.           back[i].r.statuscode=-5;
  1767.           back[i].status=0;
  1768.         }
  1769.         
  1770.       }
  1771. #endif
  1772. #if HTS_XGETHOST
  1773.       else if (back[i].status==101) {  // attendre gethostbyname
  1774. #if DEBUGDNS 
  1775.         //printf("status 101 for %s\n",back[i].url_adr);
  1776. #endif
  1777.  
  1778.         if (!gestion_timeout)
  1779.           if (back[i].timeout>0)
  1780.             gestion_timeout=1;
  1781.  
  1782.         if (host_wait(&back[i])) {    // prΩt
  1783.           back[i].status=100;        // attente connexion
  1784.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  1785.             back[i].timeout_refresh=time_local();
  1786.           }
  1787.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1788.             back[i].rateout_time=time_local();
  1789.           }
  1790.  
  1791.           back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  1792.           if (back[i].r.soc==INVALID_SOCKET) {
  1793.             back[i].status=0;  // fini, erreur
  1794.             if (back[i].r.soc!=INVALID_SOCKET) {
  1795. #if HTS_DEBUG_CLOSESOCK
  1796.               DEBUG_W("back_wait(2): deletehttp\n");
  1797. #endif
  1798.               deletehttp(&back[i].r);
  1799.             }
  1800.             back[i].r.soc=INVALID_SOCKET;
  1801.             back[i].r.statuscode=-5;
  1802.             if (strnotempty(back[i].r.msg)==0) 
  1803.               strcpybuff(back[i].r.msg,"Unable to resolve host name");
  1804.           }
  1805.         }
  1806.         
  1807.  
  1808.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  1809.       }
  1810. #endif
  1811. #if USE_BEGINTHREAD
  1812.       // ..rien α faire, c'est magic les threads
  1813. #else
  1814.       else if (back[i].status==1000) {  // en rΘception ftp
  1815.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  1816.           FILE* fp;
  1817.           fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
  1818.           if (fp) {
  1819.             int j=0;
  1820.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  1821.             while(!feof(fp)) {
  1822.               int c = fgetc(fp);
  1823.               if (c!=EOF)
  1824.                 back[i].r.msg[j++]=c;
  1825.             }
  1826.             back[i].r.msg[j++]='\0';
  1827.             fclose(fp);
  1828.             remove(fconcat(back[i].location_buffer,".ok"));
  1829.             strcpybuff(fconcat(back[i].location_buffer,".ok"),"");
  1830.           } else {
  1831.             strcpybuff(back[i].r.msg,"Unknown ftp result, check if file is ok");
  1832.             back[i].r.statuscode=-1;
  1833.           }
  1834.           back[i].status=0;
  1835.           // finalize transfer
  1836.           if (back[i].r.statuscode>0) {
  1837.             back_finalize(opt,cache,back,i);
  1838.           }
  1839.         }
  1840.       }
  1841. #endif
  1842.       else if (back[i].status==1001) {  // ftp ready
  1843.         back[i].status=0;
  1844.         // finalize transfer
  1845.         if (back[i].r.statuscode>0) {
  1846.           back_finalize(opt,cache,back,i);
  1847.         }
  1848.       }
  1849.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  1850.         int dispo=0;
  1851.         
  1852.         // vΘrifier l'existance de timeout-check
  1853.         if (!gestion_timeout)
  1854.           if (back[i].timeout>0)
  1855.             gestion_timeout=1;
  1856.           
  1857.           // donnΘes dispo?
  1858.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  1859.           if (back[i].r.is_file)
  1860.             dispo=1;
  1861.           else if (back[i].r.ssl)
  1862.             dispo=1;
  1863.           else
  1864.             dispo=FD_ISSET(back[i].r.soc,&fds);
  1865.  
  1866.           // Check transfer rate!
  1867.           if (!max_read_bytes)
  1868.             dispo=0;                // limit transfer rate
  1869.           
  1870.           if (dispo) {    // donnΘes dispo
  1871.             LLint retour_fread;
  1872.             busy_recv=1;    // on rΘcupΦre encore
  1873. #if BDEBUG==1
  1874.             printf("..data available on socket %d\n",back[i].r.soc);
  1875. #endif
  1876.  
  1877.             
  1878.             // range size hack old location
  1879.  
  1880. #if HTS_DIRECTDISK
  1881.             // Court-circuit:
  1882.             // Peut-on stocker le fichier directement sur disque?
  1883.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  1884.             if (back[i].status) {
  1885.               if (back[i].r.is_write==0) {  // mode mΘmoire
  1886.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1887.                   if (!back[i].testmode) {  // pas mode test
  1888.                     if (strnotempty(back[i].url_sav)) {
  1889.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  1890.                         if (back[i].r.statuscode==200) {  // 'OK'
  1891.                           if (!is_hypertext_mime(back[i].r.contenttype, back[i].url_fil)
  1892.                             ) {    // pas HTML
  1893.                             if (opt->getmode&2) {    // on peut ecrire des non html
  1894.                               int fcheck=0;
  1895.                               back[i].r.is_write=1;    // Θcrire
  1896.                               if (back[i].r.compressed
  1897.                                 &&
  1898.                                 /* .gz are *NOT* depacked!! */
  1899.                                 (strfield(get_ext(back[i].url_sav),"gz") == 0)
  1900.                                 ) {
  1901.                                 back[i].tmpfile_buffer[0]='\0';
  1902.                                 back[i].tmpfile=tmpnam(back[i].tmpfile_buffer);
  1903.                                 if (back[i].tmpfile != NULL && back[i].tmpfile[0])
  1904.                                   back[i].r.out=fopen(back[i].tmpfile,"wb");
  1905.                               } else {
  1906.                                 back[i].r.compressed=0;
  1907.                                 back[i].r.out=filecreate(back[i].url_sav);
  1908.                               }
  1909.                               if (back[i].r.out==NULL) {
  1910.                                 if ((fcheck=check_fatal_io_errno())) {
  1911.                                   opt->state.exit_xh=-1;   /* fatal error */
  1912.                                 }
  1913.                               }
  1914. #if HDEBUG
  1915.                               printf("direct-disk: %s\n",back[i].url_sav);
  1916. #endif
  1917.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1918.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1919.                               }
  1920.                               
  1921.                               if (back[i].r.out==NULL) {
  1922.                                 if (opt->errlog) {
  1923.                                   fspc(opt->errlog,"error");
  1924.                                   fprintf(opt->errlog,"Unable to save file %s : %s"LF,back[i].url_sav, strerror(errno));
  1925.                                   if (fcheck) {
  1926.                                     fspc(opt->errlog,"error");
  1927.                                     fprintf(opt->errlog,"* * Fatal write error, giving up"LF);
  1928.                                   }
  1929.                                   test_flush;
  1930.                                 }
  1931.                                 back[i].r.is_write=0;    // erreur, abandonner
  1932. #if HDEBUG
  1933.                                 printf("..error!\n");
  1934. #endif
  1935.                               }
  1936. #if HTS_WIN==0
  1937.                               else chmod(back[i].url_sav,HTS_ACCESS_FILE);      
  1938. #endif          
  1939.                             } else {  // on coupe tout!
  1940.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1941.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1942.                               }
  1943.                               back[i].status=0;  // terminΘ
  1944.                               if (!back[i].testmode)
  1945.                                 back[i].r.statuscode=-10;    // EUHH CANCEL
  1946.                               else
  1947.                                 back[i].r.statuscode=-10;    // "TEST OK"
  1948.                               if (back[i].r.soc!=INVALID_SOCKET) {
  1949. #if HTS_DEBUG_CLOSESOCK
  1950.                                 DEBUG_W("back_wait(3): deletehttp\n");
  1951. #endif
  1952.                                 deletehttp(&back[i].r);
  1953.                               }
  1954.                               back[i].r.soc=INVALID_SOCKET;
  1955.                             }
  1956.                           }
  1957.                         }
  1958.                       }
  1959.                     }
  1960.                   }
  1961.                 }
  1962.               }
  1963.             }
  1964. #endif              
  1965.  
  1966.             // rΘception de donnΘes depuis socket ou fichier
  1967.             if (back[i].status) {
  1968.               if (back[i].status==99)  // recevoir par bloc de lignes
  1969.                 retour_fread=http_xfread1(&(back[i].r),0);
  1970.               else if (back[i].status==98 || back[i].status==97) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  1971.                 // backuper pour lire dans le buffer chunk
  1972.                 htsblk r;
  1973.                 memcpy(&r, &(back[i].r), sizeof(htsblk));
  1974.                 back[i].r.is_write=0;                   // mΘmoire
  1975.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  1976.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  1977.                 back[i].r.totalsize=-1;                 // total inconnu
  1978.                 back[i].r.out=NULL;
  1979.                 back[i].r.is_file=0;
  1980.                 //
  1981.                 // ligne par ligne
  1982.                 retour_fread=http_xfread1(&(back[i].r),-1);
  1983.                 // modifier et restaurer
  1984.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  1985.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  1986.                 memcpy(&(back[i].r), &r, sizeof(htsblk));    // restaurer vΘritable r
  1987.               }
  1988.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  1989. #if CHUNKDEBUG==1
  1990.                 printf("[%d] read %d bytes\n",(int)back[i].r.soc,(int)min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1991. #endif
  1992.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1993.               } else              
  1994.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) max_read_bytes);
  1995.                 // retour_fread=http_fread1(&(back[i].r));
  1996.             } else
  1997.               retour_fread=READ_EOF;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  1998.             
  1999.             // Si rΘception chunk, tester si on est pas α la fin!
  2000.             if (back[i].status==1) {
  2001.               if (back[i].is_chunk) {     // attendre prochain chunk
  2002.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  2003.                   //printf("chunk end at %d\n",back[i].r.size);
  2004.                   back[i].status=97;  /* fetch ending CRLF */
  2005.                   if (back[i].chunk_adr!=NULL) { 
  2006.                     freet(back[i].chunk_adr); 
  2007.                     back[i].chunk_adr=NULL; 
  2008.                   } 
  2009.                   back[i].chunk_size=0;
  2010.                   retour_fread=0;       // pas d'erreur
  2011. #if CHUNKDEBUG==1
  2012.                   printf("[%d] waiting for current chunk CRLF..\n",(int)back[i].r.soc);
  2013. #endif
  2014.                 }
  2015.               } else if (back[i].r.keep_alive) {
  2016.                 if (back[i].r.size==back[i].r.totalsize) {      // fin!
  2017.                   retour_fread=READ_EOF;       // end
  2018.                 }
  2019.               }
  2020.             }
  2021.             
  2022.             if (retour_fread < 0) {    // fin rΘception
  2023.               back[i].status=0;    // terminΘ
  2024.              /*KA back[i].r.soc=INVALID_SOCKET; */
  2025. #if CHUNKDEBUG==1
  2026.               if (back[i].is_chunk)
  2027.                 printf("[%d] must be the last chunk for %s (connection closed) - %d/%d\n",(int)back[i].r.soc,back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  2028. #endif
  2029.               if (retour_fread < 0 && retour_fread != READ_EOF) {
  2030.                 if (back[i].r.size > 0)
  2031.                   strcatbuff(back[i].r.msg, "Interrupted transfer");
  2032.                 else
  2033.                   strcatbuff(back[i].r.msg, "No data (connection closed)");
  2034.                 back[i].r.statuscode=-4;
  2035.               } else if ((back[i].r.statuscode <= 0) && (strnotempty(back[i].r.msg)==0)) {
  2036. #if HDEBUG
  2037.                 printf("error interruped: %s\n",back[i].r.adr);
  2038. #endif        
  2039.                 if (back[i].r.size>0)
  2040.                   strcatbuff(back[i].r.msg,"Interrupted transfer");
  2041.                 else
  2042.                   strcatbuff(back[i].r.msg,"No data (connection closed)");
  2043.                 back[i].r.statuscode=-4;
  2044.               }
  2045.  
  2046.               // Close socket
  2047.               if (back[i].r.soc!=INVALID_SOCKET) {
  2048. #if HTS_DEBUG_CLOSESOCK
  2049.                 DEBUG_W("back_wait(4): deletehttp\n");
  2050. #endif
  2051.                 /*KA deletehttp(&back[i].r);*/
  2052.                 back_maydeletehttp(opt, cache, back, back_max, i);
  2053.               }
  2054.  
  2055.               // finalize transfer
  2056.               if (back[i].r.statuscode>0) {
  2057.                 back_finalize(opt,cache,back,i);
  2058.               }
  2059.  
  2060.               if (back[i].r.totalsize>0) {    // tester totalsize
  2061.               //if ((back[i].r.totalsize>0) && (back[i].status==99)) {    // tester totalsize
  2062.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  2063.                   if (!opt->tolerant) {
  2064.                     //#if HTS_CL_IS_FATAL
  2065.                     deleteaddr(&back[i].r);
  2066.                     if (back[i].r.size<back[i].r.totalsize)
  2067.                       back[i].r.statuscode=-4;        // recatch
  2068.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",(LLint)back[i].r.size,(LLint)back[i].r.totalsize);
  2069.                   } else {
  2070.                     //#else
  2071.                     // Un warning suffira..
  2072.                     if (cache->errlog!=NULL) {
  2073.                       fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  2074.                     }
  2075.                     //#endif
  2076.                   }
  2077.                 }
  2078.               }
  2079. #if BDEBUG==1
  2080.               printf("transfer ok\n");
  2081. #endif
  2082.             } else if (retour_fread > 0) {    // pas d'erreur de rΘception et data
  2083.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  2084.                 back[i].timeout_refresh=time_local();
  2085.               }
  2086.  
  2087.               // Traitement des en tΩtes chunks ou en tΩtes
  2088.               if (back[i].status==98 || back[i].status==97) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  2089.                 if (back[i].chunk_size > 0 && back[i].chunk_adr[back[i].chunk_size-1]==10) {
  2090.                   int chunk_size=-1;
  2091.                   char chunk_data[64];
  2092.                   if (back[i].chunk_size<32) {      // pas trop gros
  2093.                     char* chstrip=back[i].chunk_adr;
  2094.                     back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  2095.                     // skip leading spaces or cr
  2096.                     while(isspace(*chstrip)) chstrip++;
  2097.                     chunk_data[0] = '\0';
  2098.                     strncatbuff(chunk_data, chstrip, sizeof(chunk_data) - 2);
  2099.                     // strip chunk-extension
  2100.                     while( (chstrip = strchr(chunk_data, ';'))) *chstrip='\0';
  2101.                     while( (chstrip = strchr(chunk_data, ' '))) *chstrip='\0';
  2102.                     while( (chstrip = strchr(chunk_data, '\r'))) *chstrip='\0';
  2103. #if CHUNKDEBUG==1
  2104.                     printf("[%d] chunk received and read: %s\n",(int)back[i].r.soc,chunk_data);
  2105. #endif
  2106.                     if (back[i].r.totalsize<0)
  2107.                       back[i].r.totalsize=0;        // initialiser α 0
  2108.                     if (back[i].status==98) {   // "real" chunk
  2109.                       if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  2110.                         if (chunk_size > 0)
  2111.                           back[i].chunk_blocksize = chunk_size;  /* the data block chunk size */
  2112.                         else
  2113.                           back[i].chunk_blocksize = -1;  /* ending */
  2114.                         back[i].r.totalsize+=chunk_size;    // noter taille
  2115.                         back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
  2116.                         if (!back[i].r.adr) {
  2117.                           if (cache->errlog!=NULL) {
  2118.                             fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  2119.                           }
  2120.                         }
  2121. #if CHUNKDEBUG==1
  2122.                         printf("[%d] chunk length: %d - next total "LLintP":\n",(int)back[i].r.soc,(int)chunk_size,(LLint)back[i].r.totalsize);
  2123. #endif
  2124.                       } else {
  2125.                         if (cache->errlog!=NULL) {
  2126.                           fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  2127.                         }
  2128.                       }
  2129.                     } else {   /* back[i].status==97 : just receiving ending CRLF after data */
  2130.                       if (chunk_data[0] == '\0') {
  2131.                         if (back[i].chunk_blocksize > 0)
  2132.                           chunk_size=(int)back[i].chunk_blocksize;  /* recent data chunk size */
  2133.                         else if (back[i].chunk_blocksize == -1)
  2134.                           chunk_size=0;                        /* ending chunk */
  2135.                         else
  2136.                           chunk_size=1;                        /* fake positive size for 1st chunk history */
  2137. #if CHUNKDEBUG==1
  2138.                         printf("[%d] chunk CRLF seen\n", (int)back[i].r.soc);
  2139. #endif
  2140.                       } else {
  2141.                         if (cache->errlog!=NULL) {
  2142.                           fprintf(cache->errlog,"Warning: Illegal chunk CRLF (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  2143.                         }
  2144. #if CHUNKDEBUG==1
  2145.                         printf("[%d] chunk CRLF ERROR!! : '%s'\n", (int)back[i].r.soc, chunk_data);
  2146. #endif
  2147.                       }
  2148.                     }
  2149.                   } else {                                  
  2150.                     if (cache->errlog!=NULL) {
  2151.                       fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,(LLint)back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  2152.                     }
  2153.                   }
  2154.                     
  2155.                   // ok, continuer sur le body
  2156.                     
  2157.                   // si chunk non nul continuer (ou commencer)
  2158.                   if (back[i].status==97 && chunk_size > 0) {
  2159.                     back[i].status = 98;  /* waiting for next chunk (NN\r\n<data>\r\nNN\r\n<data>..\r\n0\r\n\r\n) */
  2160. #if CHUNKDEBUG==1
  2161.                     printf("[%d] waiting for next chunk\n", (int)back[i].r.soc);
  2162. #endif
  2163.                   } else if (back[i].status==98 && chunk_size == 0) {  /* final chunk */
  2164.                     back[i].status=97;  /* final CRLF */
  2165. #if CHUNKDEBUG==1
  2166.                     printf("[%d] waiting for final CRLF (chunk)\n", (int)back[i].r.soc);
  2167. #endif
  2168.                   } else if (back[i].status==98 && chunk_size >= 0) {  /* will fetch data now */
  2169.                     back[i].status=1;     // continuer body    
  2170. #if CHUNKDEBUG==1
  2171.                     printf("[%d] waiting for body (chunk)\n", (int)back[i].r.soc);
  2172. #endif
  2173.                   } else {                /* zero-size-chunk-CRLF (end) or error */
  2174. #if CHUNKDEBUG==1
  2175.                     printf("[%d] chunk end, total: %d\n",(int)back[i].r.soc,back[i].r.size);
  2176. #endif
  2177.                     /* End */
  2178.                     //if (back[i].status==97) {
  2179.                     back[i].status=0;     // fin  
  2180.                     //}
  2181.  
  2182.                     // finalize transfer
  2183.                     back_finalize(opt,cache,back,i);
  2184.                     if (back[i].r.soc!=INVALID_SOCKET) {
  2185. #if HTS_DEBUG_CLOSESOCK
  2186.                       DEBUG_W("back_wait(5): deletehttp\n");
  2187. #endif
  2188.                       /* Error */
  2189.                       if (chunk_size < 0) {
  2190.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2191.                         deleteaddr(&back[i].r);
  2192.                         back[i].r.statuscode=-1;
  2193.                         strcpybuff(back[i].r.msg,"Invalid chunk");
  2194. #if CHUNKDEBUG==1
  2195.                         printf("[%d] chunk error\n", (int)back[i].r.soc);
  2196. #endif
  2197.                       } else /* if chunk_size == 0 */ {
  2198. #if CHUNKDEBUG==1
  2199.                         printf("[%d] all chunks now received\n", (int)back[i].r.soc);
  2200. #endif
  2201.                           
  2202.                         /* Tester totalsize en fin de chunk */
  2203.                         if ((back[i].r.totalsize>0)) {    // tester totalsize
  2204.                           if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  2205.                             if (!opt->tolerant) {
  2206.                               deleteaddr(&back[i].r);
  2207.                               back[i].r.statuscode=-1;
  2208.                               strcpybuff(back[i].r.msg,"Incorrect length");
  2209.                             } else {
  2210.                               // Un warning suffira..
  2211.                               if (cache->errlog!=NULL) {
  2212.                                 fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,(LLint)back[i].r.size,(LLint)back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  2213.                               }
  2214.                             }
  2215.                           }
  2216.                         }
  2217.                           
  2218.                         /* Oops, trailers! */
  2219.                         if (back[i].r.keep_alive_trailers) {
  2220.                           /* fixme (not yet supported) */
  2221.                         }
  2222.                           
  2223.                       }
  2224.                         
  2225.                         
  2226.                     }
  2227.                   }
  2228.                     
  2229.                   // effacer buffer (chunk en tete)
  2230.                   if (back[i].chunk_adr!=NULL) {
  2231.                     freet(back[i].chunk_adr);
  2232.                     back[i].chunk_adr=NULL;
  2233.                     back[i].chunk_size=0;
  2234.                     // NO! xxback[i].chunk_blocksize = 0;
  2235.                   }
  2236.                   
  2237.                 } // taille buffer chunk > 1 && LF
  2238.                 //
  2239.               } else if (back[i].status==99) {        // en tΩtes (avant le chunk si il est prΘsent)
  2240.                 //
  2241.                 if (back[i].r.size>=2) {
  2242.                   // double LF
  2243.                   if (
  2244.                     ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) 
  2245.                     ||
  2246.                     (back[i].r.adr[0] == '<')    /* bogus server */
  2247.                     ) {
  2248.                     char rcvd[2048];
  2249.                     int ptr=0;
  2250.                     int noFreebuff=0;
  2251.                     
  2252. #if BDEBUG==1
  2253.                     printf("..ok, header received\n");
  2254. #endif
  2255.                     
  2256.                     
  2257.                     /* Hack for zero-length headers */
  2258.                     if (back[i].status != 0 && back[i].r.adr[0] != '<') {
  2259.                       
  2260.                       // ----------------------------------------
  2261.                       // traiter en-tΩte!
  2262.                       // status-line α rΘcupΘrer
  2263.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  2264.                       if (strnotempty(rcvd)==0) {
  2265.                         /* Bogus CRLF, OR recycled connection and trailing chunk CRLF */
  2266.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  2267.                       }
  2268.                       
  2269.                       // traiter status-line
  2270.                       treatfirstline(&back[i].r,rcvd);
  2271.                       
  2272. #if HDEBUG
  2273.                       printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  2274. #endif
  2275.                       if (_DEBUG_HEAD) {
  2276.                         if (ioinfo) {
  2277.                           fprintf(ioinfo,"[%d] response for %s%s:\r\ncode=%d\r\n",
  2278.                             back[i].r.debugid, jump_identification(back[i].url_adr),back[i].url_fil,back[i].r.statuscode);
  2279.                           fprintfio(ioinfo,back[i].r.adr,">>> ");
  2280.                           fprintf(ioinfo,"\r\n");
  2281.                           fflush(ioinfo);
  2282.                         }                    // en-tΩte
  2283.                       }
  2284.                       
  2285.                       // header // ** !attention! HTTP/0.9 non supportΘ
  2286.                       do {
  2287.                         ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  2288. #if HDEBUG
  2289.                         printf("(buffer)>%s\n",rcvd);      
  2290. #endif
  2291.                         /*
  2292.                         if (_DEBUG_HEAD) {
  2293.                         if (ioinfo) {
  2294.                         fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  2295.                         fflush(ioinfo);
  2296.                         }
  2297.                         }
  2298.                         */
  2299.                         
  2300.                         if (strnotempty(rcvd))
  2301.                           treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  2302.                         
  2303.                         // parfois les serveurs buggΘs renvoient un content-range avec un 200
  2304.                         if (back[i].r.statuscode==200)  // 'OK'
  2305.                           if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  2306.                             back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  2307.                           
  2308.                       } while(strnotempty(rcvd));
  2309.                       // ----------------------------------------                    
  2310.  
  2311.                     } else {
  2312.                       // assume text/html, OK
  2313.                       treatfirstline(&back[i].r, back[i].r.adr);
  2314.                       noFreebuff=1;
  2315.                     }
  2316.                       
  2317.                     // Callback
  2318. #if HTS_ANALYSTE
  2319.                     if (hts_htmlcheck_receivehead != NULL) {
  2320.                       int test_head=hts_htmlcheck_receivehead(back[i].r.adr, back[i].url_adr, back[i].url_fil, back[i].referer_adr, back[i].referer_fil, &back[i].r);
  2321.                       if (test_head!=1) {
  2322.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  2323.                           fspc(opt->log,"warning"); fprintf(opt->log,"External wrapper aborted transfer, breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2324.                         }
  2325.                         back[i].status=0;  // FINI
  2326.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2327.                         strcpybuff(back[i].r.msg,"External wrapper aborted transfer");
  2328.                         back[i].r.statuscode = -1;
  2329.                       }
  2330.                     }
  2331. #endif
  2332.  
  2333.                     // Free headers memory now
  2334.                     // Actually, save them for informational purpose
  2335.                     if (!noFreebuff) {
  2336.                       char* block = back[i].r.adr;
  2337.                       back[i].r.adr = NULL;
  2338.                       deleteaddr(&back[i].r);
  2339.                       back[i].r.headers = block;
  2340.                     }                  
  2341.                     
  2342.                     /* 
  2343.                     Status code and header-response hacks
  2344.                     */
  2345.  
  2346.                     
  2347.                     // Check response : 203 == 200
  2348.                     if (back[i].r.statuscode==203) {  // 'Non-Authoritative Information'
  2349.                       back[i].r.statuscode=200;       // forcer "OK"
  2350.                     } else if (back[i].r.statuscode == 100) {
  2351.                       back[i].status=99;
  2352.                       back[i].r.size=0;
  2353.                       back[i].r.totalsize=0;
  2354.                       back[i].chunk_size=0;
  2355.                       back[i].r.statuscode=-1;
  2356.                       back[i].r.msg[0]='\0';
  2357.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2358.                         fspc(opt->log,"debug"); fprintf(opt->log,"Status 100 detected for %s%s, continuing headers"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2359.                       }
  2360.                       continue;
  2361.                     }
  2362.                     
  2363.                     /*
  2364.                     Solve "false" 416 problems
  2365.                     */
  2366.                     if (back[i].r.statuscode==416) {  // 'Requested Range Not Satisfiable'
  2367.                       // Example:
  2368.                       // Range: bytes=2830-
  2369.                       // ->
  2370.                       // Content-Range: bytes */2830
  2371.                       if (back[i].range_req_size == back[i].r.crange) {
  2372.                         filenote(back[i].url_sav,NULL);
  2373.                         //xxusercommand(opt,0,NULL,back[i].url_sav,back[i].url_adr,back[i].url_fil);
  2374.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2375.                         back[i].status=0;    // READY
  2376.                         back[i].r.size=back[i].r.totalsize=back[i].range_req_size;
  2377.                         back[i].r.statuscode=304;     // NOT MODIFIED
  2378.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  2379.                           fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (good 416 message), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2380.                         }
  2381.                       }
  2382.                     }
  2383.                     
  2384.                     // transform 406 into 200 ; we'll catch embedded links inside the choice page
  2385.                     if (back[i].r.statuscode==406) {  // 'Not Acceptable'
  2386.                       back[i].r.statuscode=200;
  2387.                     }
  2388.  
  2389.                     // Various hacks to limit re-transfers when updating a mirror
  2390.                     // Force update if same size detected
  2391.                     if (opt->sizehack) {
  2392.                       // We already have the file
  2393.                       // and ask the remote server for an update
  2394.                       // Some servers, especially dynamic pages severs, always
  2395.                       // answer that the page has been modified since last visit
  2396.                       // And answer with a 200 (OK) response, and the same page
  2397.                       // If the size is the same, and the option has been set, we assume
  2398.                       // that the file is identical - and therefore let's break the connection
  2399.                       if (back[i].is_update) {          // mise α jour
  2400.                         if (back[i].r.statuscode==200 && !back[i].testmode) {  // 'OK'
  2401.                           htsblk r = cache_read(opt,cache,back[i].url_adr,back[i].url_fil,NULL,NULL);    // lire entrΘe cache
  2402.                           if (r.statuscode == 200) {  // OK pas d'erreur cache
  2403.                             LLint len1,len2;
  2404.                             len1=r.totalsize;
  2405.                             len2=back[i].r.totalsize;
  2406.                             if (r.size>0)
  2407.                               len1=r.size;
  2408.                             if (len1>0) {
  2409.                               if (len1 == len2) {             // tailles identiques
  2410.                                 back[i].r.statuscode=304;     // forcer NOT MODIFIED
  2411.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2412.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  2413.                                   fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2414.                                 }
  2415.                               }
  2416.                             }
  2417.                           } else {
  2418.                             if (opt->errlog!=NULL) {
  2419.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"File seems complete (same size), but there was a cache read error: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2420.                             }
  2421.                           }
  2422.                           if (r.adr) {
  2423.                             freet(r.adr);
  2424.                           }
  2425.                         }
  2426.                       }
  2427.                     }
  2428.                     
  2429.                     // Various hacks to limit re-transfers when updating a mirror
  2430.                     // Detect already downloaded file (with another browser, for example)
  2431.                     if (opt->sizehack) {
  2432.                       if (!back[i].is_update) {          // mise α jour
  2433.                         if (back[i].r.statuscode==200 && !back[i].testmode) {  // 'OK'
  2434.                           if (!is_hypertext_mime(back[i].r.contenttype, back[i].url_fil)) {    // not HTML
  2435.                             if (strnotempty(back[i].url_sav)) {  // target found
  2436.                               int size = fsize(back[i].url_sav);  // target size
  2437.                               if (size >= 0) {
  2438.                                 if (back[i].r.totalsize == size) {  // same size!
  2439.                                   deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2440.                                   back[i].status=0;    // READY
  2441.                                   back[i].r.size=back[i].r.totalsize;
  2442.                                   filenote(back[i].url_sav,NULL);
  2443.                                   //xxusercommand(opt,0,NULL,back[i].url_sav,back[i].url_adr,back[i].url_fil);
  2444.                                   back[i].r.statuscode=304;     // NOT MODIFIED
  2445.                                   if ((opt->debug>1) && (opt->log!=NULL)) {
  2446.                                     fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size file discovered), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2447.                                   }
  2448.                                 }
  2449.                               }
  2450.                             }
  2451.                           }
  2452.                         }
  2453.                       }
  2454.                     }
  2455.                     
  2456.                     // Various hacks to limit re-transfers when updating a mirror
  2457.                     // Detect bad range: header
  2458.                     if (opt->sizehack) {
  2459.                       // We have request for a partial file (with a 'Range: NNN-' header)
  2460.                       // and received a complete file notification (200), with 'Content-length: NNN'
  2461.                       // it might be possible that we had the complete file
  2462.                       // this is the case in *most* cases, so break the connection
  2463.                       if (back[i].r.is_write==0) {  // mode mΘmoire
  2464.                         if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  2465.                           if (!back[i].testmode) {  // pas mode test
  2466.                             if (strnotempty(back[i].url_sav)) {
  2467.                               if (strcmp(back[i].url_fil,"/robots.txt")) {
  2468.                                 if (back[i].r.statuscode==200) {  // 'OK'
  2469.                                   if (!is_hypertext_mime(back[i].r.contenttype, back[i].url_fil)) {    // pas HTML
  2470.                                     if (back[i].r.statuscode==200) {      // "OK"
  2471.                                       if (back[i].range_req_size>0) {     // but Range: requested
  2472.                                         if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  2473. #if HTS_DEBUG_CLOSESOCK
  2474.                                           DEBUG_W("back_wait(skip_range): deletehttp\n");
  2475. #endif
  2476.                                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2477.                                           back[i].status=0;    // READY
  2478.                                           back[i].r.size=back[i].r.totalsize;
  2479.                                           filenote(back[i].url_sav,NULL);
  2480.                                           //xxusercommand(opt,0,NULL,back[i].url_sav,back[i].url_adr,back[i].url_fil);
  2481.                                           back[i].r.statuscode=304;     // NOT MODIFIED
  2482.                                           if ((opt->debug>1) && (opt->log!=NULL)) {
  2483.                                             fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (reget failed), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2484.                                           }
  2485.                                         }
  2486.                                       }
  2487.                                     }
  2488.                                     
  2489.                                   }
  2490.                                 }
  2491.                               }
  2492.                             }
  2493.                           }
  2494.                         }
  2495.                       }
  2496.                     }
  2497.                     // END - Various hacks to limit re-transfers when updating a mirror
  2498.  
  2499.                     /* 
  2500.                     End of status code and header-response hacks
  2501.                     */
  2502.  
  2503.                     
  2504.                     
  2505.                     /* Interdiction taille par le wizard? */
  2506.                     if (back[i].r.soc!=INVALID_SOCKET) {
  2507.                       if (!back_checksize(opt,&back[i],1)) {
  2508.                         back[i].status=0;  // FINI
  2509.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2510.                         if (!back[i].testmode)
  2511.                           strcpybuff(back[i].r.msg,"File too big");
  2512.                         else
  2513.                           strcpybuff(back[i].r.msg,"Test: File too big");
  2514.                       }
  2515.                     }
  2516.                     
  2517.                     /* sinon, continuer */
  2518.                     /* if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body? */
  2519.                     // head: terminΘ
  2520.                     if (back[i].head_request) {
  2521.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  2522.                         fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2523.                       }
  2524. #if HTS_DEBUG_CLOSESOCK
  2525.                       DEBUG_W("back_wait(head request): deletehttp\n");
  2526. #endif
  2527.                       // Couper connexion
  2528.                       if (!back[i].http11) {    /* NO KA */
  2529.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2530.                       }
  2531.                       back[i].status=0;  // terminΘ
  2532.                     }
  2533.                     // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  2534.                     else if (back[i].r.statuscode==304) {  // document α jour dans le cache
  2535.                       // lire dans le cache
  2536.                       // ** NOTE: pas de vΘrif de la taille ici!!
  2537. #if HTS_DEBUG_CLOSESOCK
  2538.                       DEBUG_W("back_wait(file is not modified): deletehttp\n");
  2539. #endif
  2540.                       /* clear everything but connection: switch, close, and reswitch */
  2541.                       {
  2542.                         htsblk tmp;
  2543.                         memset(&tmp, 0, sizeof(tmp));
  2544.                         back_connxfr(&back[i].r, &tmp);
  2545.                         back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav,back[i].location_buffer);
  2546.                         back[i].r.location=back[i].location_buffer;
  2547.                         back_connxfr(&tmp,&back[i].r);
  2548.                       }
  2549.  
  2550.                       // hack:
  2551.                       // In case of 'if-unmodified-since' hack, a 304 status can be sent
  2552.                       // then, force 'ok' status
  2553.                       if (back[i].r.statuscode == -1) {
  2554.                         if (fexist(back[i].url_sav)) {
  2555.                           back[i].r.statuscode=200;     // OK
  2556.                           strcpybuff(back[i].r.msg, "OK (cached)");
  2557.                           back[i].r.is_file=1;
  2558.                           back[i].r.totalsize = back[i].r.size = fsize(back[i].url_sav);
  2559.                           get_httptype(back[i].r.contenttype, back[i].url_sav, 1);
  2560.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  2561.                             fspc(opt->log,"debug"); fprintf(opt->log,"Not-modified status without cache guessed: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2562.                           }
  2563.                         }
  2564.                       }
  2565.  
  2566.                       // Status is okay?
  2567.                       if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  2568.                         back[i].status=0;         // OK prΩt
  2569.                         back[i].r.notmodified=1;  // NON modifiΘ!
  2570.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  2571.                           fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2572.                         }
  2573.  
  2574.                         // finalize
  2575.                         if (back[i].r.statuscode>0) {
  2576.                           back_finalize(opt,cache,back,i);
  2577.                         }
  2578.                         
  2579. #if DEBUGCA
  2580.                         printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  2581. #endif
  2582.                         
  2583.                         //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  2584.                       } else {  // erreur
  2585.                         back[i].status=0;  // terminΘ
  2586.                         //printf("erreur cache\n");
  2587.                         
  2588.                       } 
  2589.                       
  2590. /********** NO - must complete the body! ********** */
  2591. #if 0
  2592.                     } else if ((back[i].r.statuscode==301)
  2593.                       || (back[i].r.statuscode==302)
  2594.                       || (back[i].r.statuscode==303)
  2595.                       || (back[i].r.statuscode==307)
  2596.                       || (back[i].r.statuscode==412)
  2597.                       || (back[i].r.statuscode==416)
  2598.                       ) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  2599. #if HTS_DEBUG_CLOSESOCK
  2600.                       DEBUG_W("back_wait(301,302,303,307,412,416..): deletehttp\n");
  2601. #endif
  2602.                       // Couper connexion
  2603.                       /*KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;*/
  2604.                       back_maydeletehttp(opt, cache, back, back_max, i);
  2605.  
  2606.                       back[i].status=0;  // terminΘ
  2607.                       // finalize
  2608.                       if (back[i].r.statuscode>0) {
  2609.                         back_finalize(opt,cache,back,i);
  2610.                       }
  2611. #endif
  2612. /********** **************************** ********** */
  2613.                     } else {    // il faut aller le chercher
  2614.                       
  2615.                       // effacer buffer (requΦte)
  2616.                       if (!noFreebuff) {
  2617.                         deleteaddr(&back[i].r);
  2618.                         back[i].r.size=0;
  2619.                       }
  2620.                       
  2621.                       // traiter 206 (partial content)
  2622.                       // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  2623.                       if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  2624.                         LLint sz=fsize(back[i].url_sav);
  2625. #if HDEBUG
  2626.                         printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  2627. #endif
  2628.                         if (sz>=0) {
  2629.                           if (!is_hypertext_mime(back[i].r.contenttype, back[i].url_sav)) {    // pas HTML
  2630.                             if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  2631.                               filenote(back[i].url_sav,NULL);    // noter fichier comme connu
  2632.                               back[i].r.out=fopen(fconv(back[i].url_sav),"ab");  // append
  2633.                               if (back[i].r.out) {
  2634.                                 back[i].r.is_write=1;    // Θcrire
  2635.                                 back[i].r.size=sz;    // dΘja Θcrit
  2636.                                 back[i].r.statuscode=200;  // Forcer 'OK'
  2637.                                 if (back[i].r.totalsize>0)
  2638.                                   back[i].r.totalsize+=sz;    // plus en fait
  2639.                                 fseek(back[i].r.out,0,SEEK_END);  // α la fin
  2640. #if HDEBUG
  2641.                                 printf("continue interrupted file\n");
  2642. #endif
  2643.                               } else {    // On est dans la m**
  2644.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2645.                                 strcpybuff(back[i].r.msg,"Can not open partial file");
  2646.                               }
  2647.                             }
  2648.                           } else {    // mΘmoire
  2649.                             FILE* fp=fopen(fconv(back[i].url_sav),"rb");
  2650.                             if (fp) {
  2651.                               LLint alloc_mem=sz + 1;
  2652.                               if (back[i].r.totalsize>0)
  2653.                                 alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  2654.                               if ( deleteaddr(&back[i].r) && (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
  2655.                                 back[i].r.size=sz;
  2656.                                 if (back[i].r.totalsize>0)
  2657.                                   back[i].r.totalsize+=sz;    // plus en fait
  2658.                                 if (( fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
  2659.                                   back[i].status=0;  // terminΘ (voir plus loin)
  2660.                                   strcpybuff(back[i].r.msg,"Can not read partial file");
  2661.                                 } else {
  2662.                                   back[i].r.statuscode=200;  // Forcer 'OK'
  2663. #if HDEBUG
  2664.                                   printf("continue in mem interrupted file\n");
  2665. #endif
  2666.                                 }
  2667.                               } else {
  2668.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2669.                                 strcpybuff(back[i].r.msg,"No memory for partial file");
  2670.                               }
  2671.                               fclose(fp);
  2672.                             } else {  // Argh.. 
  2673.                               back[i].status=0;  // terminΘ (voir plus loin)
  2674.                               strcpybuff(back[i].r.msg,"Can not open partial file");
  2675.                             }
  2676.                           }
  2677.                         } else {    // Non trouvΘ??
  2678.                           back[i].status=0;  // terminΘ (voir plus loin)
  2679.                           strcpybuff(back[i].r.msg,"Can not find partial file");
  2680.                         }
  2681.                         // Erreur?
  2682.                         if (back[i].status==0) {
  2683.                           if (back[i].r.soc!=INVALID_SOCKET) {
  2684. #if HTS_DEBUG_CLOSESOCK
  2685.                             DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  2686. #endif
  2687.                             deletehttp(&back[i].r);
  2688.                           }
  2689.                           back[i].r.soc=INVALID_SOCKET;
  2690.                           //back[i].r.statuscode=206;  ????????
  2691.                           back[i].r.statuscode=-5;
  2692.                           if (strnotempty(back[i].r.msg))
  2693.                             strcpybuff(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  2694.                         }
  2695.                       }
  2696.                       
  2697.                       if (back[i].status!=0) {  // non terminΘ (erreur)
  2698.                         if (!back[i].testmode) {    // fichier normal
  2699.                           
  2700.                           if (back[i].r.empty /* ?? && back[i].r.statuscode==200 */) {  // empty response
  2701.                             // Couper connexion
  2702.                             back_maydeletehttp(opt, cache, back, back_max, i);
  2703.                             /* KA deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET; */
  2704.                             back[i].status=0;  // terminΘ
  2705.                             if ( deleteaddr(&back[i].r) && (back[i].r.adr=(char*) malloct((INTsys) 2)) ) {
  2706.                               back[i].r.adr[0] = 0;
  2707.                             }
  2708.                             back_finalize(opt,cache,back,i);
  2709.                           }
  2710.                           else if (!back[i].r.is_chunk) {    // pas de chunk
  2711.                             //if (back[i].r.http11!=2) {    // pas de chunk
  2712.                             back[i].is_chunk=0;
  2713.                             back[i].status=1;     // start body
  2714.                           } else {
  2715. #if CHUNKDEBUG==1
  2716.                             printf("[%d] chunk encoding detected %s..\n",(int)back[i].r.soc, back[i].url_fil);
  2717. #endif
  2718.                             back[i].is_chunk=1;
  2719.                             back[i].chunk_adr=NULL;
  2720.                             back[i].chunk_size=0;
  2721.                             back[i].chunk_blocksize=0;
  2722.                             back[i].status=98;    // start body wait chunk
  2723.                             back[i].r.totalsize=0;   /* devalidate size! (rfc) */
  2724.                           }
  2725.                           if (back[i].rateout>0) {
  2726.                             back[i].rateout_time=time_local();  // refresh pour transfer rate
  2727.                           }
  2728. #if HDEBUG
  2729.                           printf("(buffer) start body!\n");
  2730. #endif
  2731.                         } else {     // mode test, ne pas passer en 1!!
  2732.                           back[i].status=0;    // READY
  2733. #if HTS_DEBUG_CLOSESOCK
  2734.                           DEBUG_W("back_wait(test ok): deletehttp\n");
  2735. #endif
  2736.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2737.                           if (back[i].r.statuscode==200) {
  2738.                             strcpybuff(back[i].r.msg,"Test: OK");
  2739.                             back[i].r.statuscode=-10;    // test rΘussi
  2740.                           }
  2741.                           else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  2742.                             char tempo[1000];
  2743.                             strcpybuff(tempo,back[i].r.msg);
  2744.                             strcpybuff(back[i].r.msg,"Test: ");
  2745.                             strcatbuff(back[i].r.msg,tempo);
  2746.                           }
  2747.                           
  2748.                         }
  2749.                       }
  2750.                       
  2751.                       } 
  2752.                       
  2753.                       /*}*/
  2754.                       
  2755.                   }  // si LF
  2756.                 }  // r.size>2
  2757.               }  // si == 99
  2758.               
  2759.             } // si pas d'erreurs
  2760. #if BDEBUG==1
  2761.             printf("bytes overall: %d\n",back[i].r.size);
  2762. #endif
  2763.           }  // donnΘes dispo
  2764.           
  2765.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  2766. #if HTS_REMOVE_BAD_FILES
  2767.           if (back[i].status<0) {
  2768.             if (!back[i].testmode) {    // pas en test
  2769.               remove(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  2770.               //printf("&& %s\n",back[i].url_sav);
  2771.             }
  2772.           }
  2773. #endif
  2774.  
  2775.           /* funny log for commandline users */
  2776.           //if (!opt->quiet) {  
  2777.           // petite animation
  2778.           if (opt->verbosedisplay==1) {
  2779.             if (back[i].status==0) {
  2780.               if (back[i].r.statuscode==200)
  2781.                 printf("* %s%s ("LLintP" bytes) - OK"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size);
  2782.               else
  2783.                 printf("* %s%s ("LLintP" bytes) - %d"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,(LLint)back[i].r.size,back[i].r.statuscode);
  2784.               fflush(stdout);
  2785.             }
  2786.           }
  2787.           //}
  2788.           
  2789.  
  2790.       } // status>0
  2791.     }  // for
  2792.     
  2793.     // vΘrifier timeouts
  2794.     if (gestion_timeout) {
  2795.       TStamp act;
  2796.       act=time_local();    // temps en secondes
  2797.       for(i_mod = 0 ; i_mod < (unsigned int) back_max ; i_mod++) {
  2798.       // for(i=0;i<back_max;i++) {
  2799.         unsigned int i = ( i_mod + mod_random ) % ( back_max );     
  2800.         if (back[i].status>0) {  // rΘception/connexion/..
  2801.           if (back[i].timeout>0) {
  2802.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  2803.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  2804.               if (back[i].r.soc!=INVALID_SOCKET) {
  2805. #if HTS_DEBUG_CLOSESOCK
  2806.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  2807. #endif
  2808.                 deletehttp(&back[i].r);
  2809.               }
  2810.               back[i].r.soc=INVALID_SOCKET;
  2811.               back[i].r.statuscode=-2;
  2812.               if (back[i].status==100)
  2813.                 strcpybuff(back[i].r.msg,"Connect Time Out");
  2814.               else if (back[i].status==101)
  2815.                 strcpybuff(back[i].r.msg,"DNS Time Out");
  2816.               else
  2817.                 strcpybuff(back[i].r.msg,"Receive Time Out");
  2818.               back[i].status=0;  // terminΘ
  2819.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  2820.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  2821.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  2822.                   back[i].status=0;  // terminΘ
  2823.                   if (back[i].r.soc!=INVALID_SOCKET) {
  2824. #if HTS_DEBUG_CLOSESOCK
  2825.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  2826. #endif
  2827.                     deletehttp(&back[i].r);
  2828.                   }
  2829.                   back[i].r.soc=INVALID_SOCKET;
  2830.                   back[i].r.statuscode=-3;
  2831.                   strcpybuff(back[i].r.msg,"Transfer Rate Too Low");
  2832.                 }
  2833.               }
  2834.             }
  2835.           }
  2836.         }
  2837.       }
  2838.     }
  2839.     max_loop--;
  2840. #if HTS_ANALYSTE
  2841.     max_loop_chk++;
  2842. #endif
  2843.   } while((busy_state) && (busy_recv) && (max_loop>0));
  2844. #if HTS_ANALYSTE
  2845.   if ((!busy_recv) && (!busy_state)) {
  2846.     if (max_loop_chk>=1) {
  2847.       Sleep(10);    // un tite pause pour Θviter les lag..
  2848.     }
  2849.   }
  2850. #endif
  2851. }
  2852.  
  2853. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  2854.   LLint size_to_test;
  2855.   if (check_only_totalsize)
  2856.     size_to_test=eback->r.totalsize;
  2857.   else
  2858.     size_to_test=max(eback->r.totalsize,eback->r.size);
  2859.   if (size_to_test>=0) {
  2860.     
  2861.     /* Interdiction taille par le wizard? */
  2862.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,eback->r.totalsize/1024)==-1) {
  2863.       return 0;     /* interdit */
  2864.     }                     
  2865.     
  2866.     /* vΘrifier taille classique (heml et non html) */
  2867.     if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  2868.       return 0;     /* interdit */
  2869.     }
  2870.   }
  2871.   return 1;
  2872. }
  2873.  
  2874. int back_checkmirror(httrackp* opt) {
  2875.   // Check max time
  2876.   if ((opt->maxsite>0) && (HTS_STAT.stat_bytes >= opt->maxsite)) {
  2877.     if (opt->errlog) {
  2878.       fprintf(opt->errlog,"More than "LLintP" bytes have been transfered.. giving up"LF,(LLint)opt->maxsite);
  2879.       test_flush;
  2880.     } 
  2881.     return 0;
  2882.   } else if ((opt->maxtime>0) && ((time_local()-HTS_STAT.stat_timestart)>opt->maxtime)) {            
  2883.     if (opt->errlog) {
  2884.       fprintf(opt->errlog,"More than %d seconds passed.. giving up"LF,opt->maxtime);
  2885.       test_flush;
  2886.     } 
  2887.     return 0;
  2888.   }
  2889.   return 1;   /* Ok, go on */
  2890. }
  2891.  
  2892.  
  2893. // octets transfΘrΘs + add
  2894. LLint back_transfered(LLint nb,lien_back* back,int back_max) {
  2895.   int i;
  2896.   // ajouter octets en instance
  2897.   for(i=0;i<back_max;i++)
  2898.     if ((back[i].status>0) && (back[i].status<99 || back[i].status>=1000))
  2899.       nb+=back[i].r.size;
  2900.   return nb;      
  2901. }
  2902.  
  2903. // infos backing
  2904. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2905. void back_info(lien_back* back,int i,int j,FILE* fp) {
  2906.   if (back[i].status>=0) {
  2907.     char BIGSTK s[HTS_URLMAXSIZE*2+1024]; 
  2908.     s[0]='\0';
  2909.     back_infostr(back,i,j,s);
  2910.     strcatbuff(s,LF);
  2911.     fprintf(fp,"%s",s);
  2912.   }
  2913. }
  2914.  
  2915. // infos backing
  2916. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2917. void back_infostr(lien_back* back,int i,int j,char* s) {
  2918.   if (back[i].status>=0) {
  2919.     int aff=0;
  2920.     if (j & 1) {
  2921.       if (back[i].status==100) {
  2922.         strcatbuff(s,"CONNECT ");
  2923.       } else if (back[i].status==99) {
  2924.         strcatbuff(s,"INFOS ");
  2925.         aff=1;
  2926.       } else if (back[i].status==98 || back[i].status==97) {
  2927.         strcatbuff(s,"INFOSC");             // infos chunk
  2928.         aff=1;
  2929.       }
  2930.       else if (back[i].status>0) {
  2931. #if HTS_ANALYSTE==2
  2932.         strcatbuff(s,"WAIT ");
  2933. #else
  2934.         strcatbuff(s,"RECEIVE "); 
  2935. #endif
  2936.         aff=1; 
  2937.       }
  2938.     } 
  2939.     if (j & 2) {
  2940.       if (back[i].status==0) {
  2941.         switch (back[i].r.statuscode) {
  2942.         case 200:
  2943.           strcatbuff(s,"READY ");
  2944.           aff=1;
  2945.           break;
  2946. #if HTS_ANALYSTE==2
  2947.         default:
  2948.           strcatbuff(s,"ERROR ");
  2949.           break;
  2950. #else
  2951.         case -1:
  2952.           strcatbuff(s,"ERROR ");
  2953.           aff=1;
  2954.           break;
  2955.         case -2:
  2956.           strcatbuff(s,"TIMEOUT ");
  2957.           aff=1;
  2958.           break;
  2959.         case -3:
  2960.           strcatbuff(s,"TOOSLOW ");
  2961.           aff=1;
  2962.           break;
  2963.         case 400:
  2964.           strcatbuff(s,"BADREQUEST ");
  2965.           aff=1;
  2966.           break;
  2967.         case 401: case 403:
  2968.           strcatbuff(s,"FORBIDDEN ");
  2969.           aff=1;
  2970.           break;
  2971.         case 404:
  2972.           strcatbuff(s,"NOT FOUND ");
  2973.           aff=1;
  2974.           break;
  2975.         case 500:
  2976.           strcatbuff(s,"SERVERROR ");
  2977.           aff=1;
  2978.           break;
  2979.         default:
  2980.           {
  2981.             char s2[256];
  2982.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  2983.             strcatbuff(s,s2);
  2984.           }
  2985.           aff=1;
  2986. #endif
  2987.         }
  2988.       }
  2989.     }
  2990.     
  2991.     if (aff) {
  2992.       {
  2993.         char BIGSTK s2[HTS_URLMAXSIZE*2+1024];
  2994.         sprintf(s2,"\"%s",back[i].url_adr); strcatbuff(s,s2);
  2995.         
  2996.         if (back[i].url_fil[0]!='/') strcatbuff(s,"/");
  2997.         sprintf(s2,"%s\" ",back[i].url_fil); strcatbuff(s,s2);
  2998.         sprintf(s,LLintP" "LLintP" ",(LLint)back[i].r.size,(LLint)back[i].r.totalsize); strcatbuff(s,s2);
  2999.       }
  3000.     }
  3001.   }
  3002. }
  3003.  
  3004. // -- backing --
  3005.  
  3006. #undef test_flush
  3007.